2013年3月30日土曜日

メモ書き - TESObjectREFR::IsPlayable


TESV.exeをボーっと見てたら、こんなコードがあった。

CPU Disasm
Address   Hex dump          Command                                  Comments
0047A5D2  |.  0FB641 12     |MOVZX EAX,BYTE PTR DS:[ECX+12]          ; Switch (cases 1F..2A, 4 exits)
0047A5D6  |.  83E8 1F       |SUB EAX,1F
0047A5D9  |.  74 33         |JZ SHORT 0047A60E
0047A5DB  |.  83E8 0A       |SUB EAX,0A
0047A5DE  |.  74 1E         |JZ SHORT 0047A5FE
0047A5E0  |.  83E8 01       |SUB EAX,1
0047A5E3  |.  74 0B         |JZ SHORT 0047A5F0
0047A5E5  |.  8B01          |MOV EAX,DWORD PTR DS:[ECX]              ; Default case of switch TESV.47A5D2
0047A5E7  |.  8B50 64       |MOV EDX,DWORD PTR DS:[EAX+64]
0047A5EA  |.  FFD2          |CALL EDX
0047A5EC  |.  84C0          |TEST AL,AL
0047A5EE  |.  EB 29         |JMP SHORT 0047A619
0047A5F0  |>  8A81 90000000 |MOV AL,BYTE PTR DS:[ECX+90]             ; Case 2A of switch TESV.47A5D2
0047A5F6  |.  D0E8          |SHR AL,1
0047A5F8  |.  F6D0          |NOT AL
0047A5FA  |.  A8 01         |TEST AL,01
0047A5FC  |.  EB 1B         |JMP SHORT 0047A619
0047A5FE  |>  8A89 F2000000 |MOV CL,BYTE PTR DS:[ECX+0F2]            ; Case 29 of switch TESV.47A5D2
0047A604  |.  C0E9 07       |SHR CL,7
0047A607  |.  F6D1          |NOT CL
0047A609  |.  F6C1 01       |TEST CL,01
0047A60C  |.  EB 0B         |JMP SHORT 0047A619
0047A60E  |>  8B91 84000000 |MOV EDX,DWORD PTR DS:[ECX+84]           ; Case 1F of switch TESV.47A5D2
0047A614  |.  D1EA          |SHR EDX,1
0047A616  |.  F6C2 01       |TEST DL,01
0047A619  |>  0F84 8A000000 |JZ 0047A6A9

分かりやすいようにC++で書くと、こんな感じ

TESForm* thisForm;
bool IsPlayable;
if (thisForm->formType == kFormType_Ammo)
{
    TESAmmo* ammo = (TESAmmo*)thisForm;
    IsPlayable = (ammo->settings.flags & 2) == 0;
}
else if (thisForm->formType == kFormType_Weapon)
{
    TESObjectWeap* weap = (TESObjectWEAP*)thisForm;
    IsPlayable = (weap->gameData.flags2 & weap->gameData.kFlags_NotPlayable) == 0;
}
else if (thisForm->formType == kFormType_Light)
{
    TESObjectLIGH* ligh = (TESObjectLIGH*)thisForm;
    IsPlayable = (ligh->unk78.unk0C & 2) != 0;
}
else
{
    IsPlayable = thisForm->GetFlag00020000();
}
これでやっと、bool TESObjectREFR::IsPlayable(void) が作れるんじゃないかな!!

4 件のコメント:

  1. こんにちは
    bool TESOjectREFR::IsPlayable(void)が作ることができると、具体的にどのような恩恵があるのでしょうか?

    原語に全くの無知なので、簡単な例の紹介があると嬉しいです

    もっとも、ブログのタイトルにはそぐいませんね

    返信削除
  2. こんにちは。
    具体的な恩恵でしたら、たとえば・・・
    PapyrusでPlayableが拾えることで一番恩恵をうけるのは、Harvest のような自動採集MODだと思います。

    プレイヤーが手動でアイテムを拾うぶんには、そもそも見えないし拾えないので問題ないのですが
    自動採集MODでPlayableではないアイテムを拾ってしまうと、これは問題ですよね。
    捨てたくとも見えないアイテムで、いつのまにか荷物がいっぱい・・・みたいなことが簡単に発生します。

    Playableではないアイテムまで拾ってはまずいので、自動採集系のMODは、Playableが付いてないものを
    全部リストアップし、もしリストにあったら拾わないようにするしかなかったのです。
    でもこの方法だと、MOD追加装備のような未知のアイテムには対応できません。

    もしIsPlayable関数さえあれば、こういう手間は根本から要らなくなってしまうわけです。

    返信削除
    返信
    1. ご回答ありがとうございます

      もうすでに具体的な構想をお持ちのようですね

      また素晴らしい形で結実することを期待しています

      削除
  3. ホント助かります :)

    返信削除