NPCの情報を表示する

Modを作ろう

NPCに耐性や弱点を追加するModがあります。覚えるのは大変なので、ゲームの中でNPCの情報を表示できるようにしてみました。

NPCと防具に耐性や弱点を追加するKnow Your Enemy - Trait-based resistances and weaknessesは、何が有効で何が効かないかを覚えるのは大変なので、ゲームの中でNPCの情報を表示できるようにしてみました。

メッセージを表示するには

まずはメッセージを表示する方法からです。大きく分けて2通りあります。

CKであらかじめフォームを作っておく

フォームはMessageになります。CKでMessageを用意して、文章を入力しておきます。Message Boxにチェックを入れるとダイアログになります。ゲームが一時停止し、OKを押すまで表示され続けます。チェックを外すと通知となります。ゲームは停止せず左上に表示されてすぐに消えます。

文章はある程度はカスタマイズが可能です。ときにはQuestのReferenceAliasに適切な設定が必要となります。作る側はあれこれと大変ですが、espファイルだけで完結しているため、使う側はxTranslatorで翻訳もできて使い勝手がいいです。

フォーマットがほぼ固定で、人名や個数などをかえられる程度です。銀行や役所の申請用紙をイメージしてもらうとわかりやすいかもしれません。

スクリプトで作る

スクリプト内で文字列を生成し、Debug.MessageBoxDebug.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で設定できるようにすればいいです。

タイトルとURLをコピーしました