NPCと防具に耐性や弱点を追加するKnow Your Enemy - Trait-based resistances and weaknessesは、何が有効で何が効かないかを覚えるのは大変なので、ゲームの中でNPCの情報を表示できるようにしてみました。
メッセージを表示するには
まずはメッセージを表示する方法からです。大きく分けて2通りあります。
CKであらかじめフォームを作っておく
フォームはMessageになります。CKでMessageを用意して、文章を入力しておきます。Message Boxにチェックを入れるとダイアログになります。ゲームが一時停止し、OKを押すまで表示され続けます。チェックを外すと通知となります。ゲームは停止せず左上に表示されてすぐに消えます。
文章はある程度はカスタマイズが可能です。ときにはQuestのReferenceAliasに適切な設定が必要となります。作る側はあれこれと大変ですが、espファイルだけで完結しているため、使う側はxTranslatorで翻訳もできて使い勝手がいいです。
フォーマットがほぼ固定で、人名や個数などをかえられる程度です。銀行や役所の申請用紙をイメージしてもらうとわかりやすいかもしれません。
スクリプトで作る
スクリプト内で文字列を生成し、Debug.MessageBoxやDebug.Notificationで表示させる方法です。
文章は好きに組み立てられ、スクリプトのみで完結するので、CKでの面倒な作業がなく、とても簡単です。
日本語化は面倒で、まずスクリプトのソースコード内に日本語の文字列を埋め込めません。Papyrus CompilerがUTF-8で構成されている文字列を処理できないようです。コメントは処理の対象外なので問題ありません。
何とか翻訳に対応させるために、2つの方法を考えました。
フォームの名前を使って日本語化
日本語のメッセージを表示する・フォーム編 (papyrus)
MiscObject Property SampleItem Auto
Function PrintMessage()
String s = SampleItem.GetName()
Debug.MessageBox(s)
EndFunction
あらかじめCKでSampleItemを作っておきます。何でもいいので、MiscObject(CKだとMiscItem)にしました。MiscObjectの名前を表示します。xTraslatorで翻訳しておけば、日本語にすることもできます。
PapyrusUtil SEのContainerを使って日本語化
PapyrusUtil SEはJSON形式の外部ファイルを読み書きできるので、MCMの設定をプロファイルとして保存したりするのにとても便利です。この仕組みを使って日本語の文章をJSONファイルに入れておき、取り出して使う方法です。
こんな感じでJSONファイルを作ります。キーは小文字なので注意してください。
日本語のメッセージを表示するためのJSONファイル (json)
{
"string" :
{
"onehandedsword" : "片手剣",
"dagger" : "ダガー",
"onehandedwaraxe" : "片手斧",
"onehandedmace" : "片手棍",
"twohandedsword" : "両手剣",
"twohandedaxehammer" : "両手斧/棍",
"bow" : "弓",
"staff" : "杖",
"crossbow" : "クロスボウ",
"unknownweapon" : "武器",
"is" : "は"
}
}
これをスクリプトから取り出します。
日本語のメッセージを表示する・JSON編 (papyrus)
String MessageFile = "MyMod_Japanese.json"
String Function ExamineThisWeapon(Weapon akWeapon)
String s = akWeapon.GetName()
Int iType = akWeapon.GetWeaponType()
s += JsonUtil.GetStringValue(MessageFile, "is", " is ")
if iType == 1
s += JsonUtil.GetStringValue(MessageFile, "onehandedsword", "one handed sword")
elseif iType == 2
s += JsonUtil.GetStringValue(MessageFile, "dagger", "dagger")
elseif iType == 3
s += JsonUtil.GetStringValue(MessageFile, "onehandedwaraxe", "one handed war axe")
elseif iType == 4
s += JsonUtil.GetStringValue(MessageFile, "onehandedmace", "one handed mace")
elseif iType == 5
s += JsonUtil.GetStringValue(MessageFile, "twohandedsword", "two handed sword")
elseif iType == 6
s += JsonUtil.GetStringValue(MessageFile, "twohandedaxehammer", "two handed axe/hammer")
elseif iType == 7
s += JsonUtil.GetStringValue(MessageFile, "bow", "bow")
elseif iType == 8
s += JsonUtil.GetStringValue(MessageFile, "staff", "staff")
elseif iType == 9
s += JsonUtil.GetStringValue(MessageFile, "crossbow", "crossbow")
else
s += JsonUtil.GetStringValue(MessageFile, "unknownweapon", "weapon")
endif
Debug.MessageBox(s)
EndFunction
NPCの耐性と弱点を表示する
対象がプレイヤーと敵対しているのか、レベル差はどれくらいか、どんな耐性と弱点があるのかを表示します。
NPCの情報を表示する (papyrus)
Function Consider(Actor akTarget)
String s = akTarget.GetDisplayName()
Int iRank = akTarget.GetRelationshipRank(PlayerRef)
if akTarget.IsHostileToActor(PlayerRef)
s += JsonUtil.GetStringValue(MessageFile, "ConsiderRtA", " scrawls at you. ready to attack, ")
elseif iRank >= 3
s += JsonUtil.GetStringValue(MessageFile, "ConsiderWamly", " looks upon you wamly, ")
elseif iRank == 2
s += JsonUtil.GetStringValue(MessageFile, "ConsiderKindly", " kindly considers you, ")
elseif iRank == 1
s += JsonUtil.GetStringValue(MessageFile, "ConsiderAmiably", " judges you amiably, ")
else
s += JsonUtil.GetStringValue(MessageFile, "ConsiderIndiff", " regards you indiffrently, ")
endif
;s += "\n"
Int iDiffer = akTarget.GetLevel() - PlayerRef.GetLevel()
if iDiffer < -9
s += JsonUtil.GetStringValue(MessageFile, "Consider01", "you could probably win this fight.")
elseif iDiffer < -5
s += JsonUtil.GetStringValue(MessageFile, "Consider02", "this creature could pose problems, you would probably defeat it.")
elseif iDiffer < -2
s += JsonUtil.GetStringValue(MessageFile, "Consider03", "appears to be quite formidable.")
elseif iDiffer <= 2
s += JsonUtil.GetStringValue(MessageFile, "Consider04", "looks like an even fight")
elseif iDiffer <= 5
s += JsonUtil.GetStringValue(MessageFile, "Consider05", "looks like quite a gamble.")
elseif iDiffer <= 9
s += JsonUtil.GetStringValue(MessageFile, "Consider06", "looks like it would wipe the floor with you!")
else
s += JsonUtil.GetStringValue(MessageFile, "Consider07", "what would you like your tombstone to say?")
endif
if Game.GetModByName("know_your_enemy.esp") != 255
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA5E, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_fat", "\nFat : resist maces, axes, fire and ice")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA60, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_big", "\nBig : resist maces, axes, arrows, fire and ice")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA61, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_small", "\nSmall : weak to arrows, fire and ice")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA62, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_armored", "\nArmored : resist arrows, daggers, swords and maces")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA63, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_undead", "\nUndead : immune to disease and poison, resist daggers, swords, arrows, maces and shock, weak to axes")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA64, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_plant", "\nPlant : resist axes, weak to maces")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA65, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_skeletal", "\nSkeletal : resist arrows, daggers, swords and axes")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA66, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_brittle", "\nBrittle : weak to maces, axes and arrows")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x00AA67, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_machine", "\nMachine : immune to shock, disease and poison, resist axes, daggers, swords, arrows and fire, weak to ice")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x08E4B3, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_machine_2", " / weak to ice")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x02E171, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_ghostly", "\nGhostly : immune to physical")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047680, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_furred", "\nFurred : resist frost")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x06FE9B, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_furred_2", " / weak to fire")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047681, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_supernatural", "\nSuper Natural : immune to disease, poison")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x0A28D4, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_supernatural_2", " / weak to shock")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047682, "know_your_enemy.esp") as Perk)
if PlayerRef.HasPerk(Game.GetFormFromFile(0x0986BC, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_venomous_2", "\nVenomous : nothing (knowledge)")
else
s += JsonUtil.GetStringValue(MessageFile, "perk_venomous", "\nVenomous : immune to poison")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047683, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_ice_elemental", "\nIce : immune to ice, weak to fire")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x09D7C1, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_ice_elemental_2", " / weak to fire")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047684, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_fire_elemental", "\nFire : immune to fire, weak to ice")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x09D7C1, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_fire_elemental_2", " / weak to ice")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047685, "know_your_enemy.esp") as Perk)
if PlayerRef.HasPerk(Game.GetFormFromFile(0x09D7C1, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_shock_elemental_2", "\nShock : nothing (knowledge)")
else
s += JsonUtil.GetStringValue(MessageFile, "perk_shock_elemental", "\nShock : immune to shock")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047686, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_vile", "\nVile : resist disease")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x0A28C9, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_vile_2", " / weak to ice")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047687, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_troll_kin", "\nTroll Kin : weak to fire")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x0A28CB, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_troll_kin_2", " / weak to fire")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047688, "know_your_enemy.esp") as Perk)
if PlayerRef.HasPerk(Game.GetFormFromFile(0x0A28CB, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_weak_willed_2", "\nWeak Willed : weak to magic (knowledge)")
else
s += JsonUtil.GetStringValue(MessageFile, "perk_weak_willed", "\nWeak Willed : nothing")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x047689, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_strong_willed", "\nStrong Willed : resist shock, fire and ice")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x04768A, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_cave_dwelling", "\nCave Dwelling : resist poison, weak to disease")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x0A28CE, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_cave_dwelling_2", " / weak to fire")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x04768B, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_vascular", "\nVascular : weak to daggers, swords and poison")
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x04768C, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_aquatic", "\nAquatic : resist fire, weak to shock")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x0A28D0, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_aquatic_2", " / weak to ice")
endif
endif
if akTarget.HasPerk(Game.GetFormFromFile(0x04C78E, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_rocky", "\nRocky : resist arrows, daggers, swords, axes, maces, fire and shock")
if PlayerRef.HasPerk(Game.GetFormFromFile(0x0A28D7, "know_your_enemy.esp") as Perk)
s += JsonUtil.GetStringValue(MessageFile, "perk_rocky_2", " / weak to ice")
endif
endif
endif
Debug.MessageBox(s)
EndFunction
これをホットキーが押されたらGame.GetCurrentCrosshairRefで捕捉したNPCに使ったり、スペルで使ったりすれば完成です。
知識を得ると弱点が増えます。動的に反映させるようにしてあります。弱い意志が「なし」ですが、知識を得た後は「氷に弱い」にかわります。
防具の耐性と弱点を表示する
対象が装備している情報を表示させてみます。
防具の耐性と弱点を表示する (papyrus)
Function ExamineEquipments(Actor akTarget)
String s
Int iThisSlot = 0x01
Int iSlotsChecked = 0x00100000 + 0x00200000 ; チェックを省くスロット
while iThisSlot < 0x80000000
if Math.LogicalAnd(iSlotsChecked, iThisSlot) != iThisSlot
Armor kArmor = akTarget.GetWornForm(iThisSlot) as Armor
if kArmor
iSlotsChecked += kArmor.GetSlotMask()
if kArmor.IsPlayable() && ( kArmor.IsHeavyArmor() || kArmor.IsLightArmor() )
if s
s += "\n"
endif
s += ExamineThisArmor(kArmor, akTarget, iThisSlot)
endif
else
iSlotsChecked += iThisSlot
endif
endif
iThisSlot *= 2
endwhile
if s
Debug.MessageBox(s)
endif
EndFunction
String Function ExamineThisArmor(Armor akArmor, ObjectReference akTargetRef, Int aiSlotMask = 0)
String s = akArmor.GetName()
Float fHealth
if akTargetRef as Actor
fHealth = WornObject.GetItemHealthPercent(akTargetRef as Actor, handSlot = 0, slotMask = aiSlotMask)
else
fHealth = akTargetRef.GetItemHealthPercent()
endif
s += " (" + Math.Floor( (fHealth - 1.0) * 1000.0 ) + ")" ; 切り下げないとEDSの表示と合わない
if Game.GetModByName(KYE_File) != 255
if akArmor.HasKeywordString("kye_armor_warm")
s += JsonUtil.GetStringValue(MessageFile, "armor_warm", "\nWarm : weak to arrows, resist ice")
endif
if akArmor.HasKeywordString("kye_armor_leathery")
s += JsonUtil.GetStringValue(MessageFile, "armor_leathery", "\nLeathery : weak to arrows, resist fire")
endif
if akArmor.HasKeywordString("kye_armor_brittle")
s += JsonUtil.GetStringValue(MessageFile, "armor_brittle", "\nBrittle : weak to maces")
endif
if akArmor.HasKeywordString("kye_armor_nonconductive")
s += JsonUtil.GetStringValue(MessageFile, "armor_nonconductive", "\nNonconductive : resist shock, weak to fire and ice")
endif
if akArmor.HasKeywordString("kye_armor_thick")
s += JsonUtil.GetStringValue(MessageFile, "armor_thick", "\nThick : resist arrows, daggers and swords")
endif
if akArmor.HasKeywordString("kye_armor_metal")
s += JsonUtil.GetStringValue(MessageFile, "armor_metal", "\nMetal : resist arrows, daggers and swords, weak to fire, ice and shock")
endif
if akArmor.HasKeywordString("kye_armor_layered")
s += JsonUtil.GetStringValue(MessageFile, "armor_layered", "\nLayered : resist arrows")
endif
if akArmor.HasKeywordString("kye_armor_deep")
s += JsonUtil.GetStringValue(MessageFile, "armor_deep", "\nDeep : resist maces and axes")
endif
endif
return s
EndFunction
プレイヤーに使ってみた結果です。ちなみに耐性と弱点は胴装備(ArmorCuirassキーワードを持つ防具)にだけあります。
他の言語に対応させるには
JSONファイルを言語ごとに用意しておき、参照するJSONファイルをMCMで設定できるようにすればいいです。