2019年12月15日日曜日

Mote-Includeの装備セット選びの基本アルゴリズム


Mote-IncludeはWSや魔法、アビリティごとに装備セットを簡単に設定できてとても便利。
GitHubにあるジョブごとのサンプルテンプレートを見ると、たとえば、

sets.precast.JA['Mana Wall'] = {feet="Goetia Sabots +2"}
sets.precast.JA.Manafont = {body="Sorcerer's Coat +2"}
sets.precast.FC = {ammo="Impatiens", head="Nahtirah Hat",
                             ear2="Loquacious Earring",
                             body="Vanir Cotehardie",ring1="Prolix Ring",
                             back="Swith Cape +1",waist="Witful Belt",
                             legs="Orvail Pants +1",feet="Chelona Boots +1"}
sets.precast.FC.Cure = set_combine(sets.precast.FC,
                             {body="Heka's Kalasiris", back="Pahtli Cape"})

こんな風に各アクションごとに装備するセット内容を指定できる。Mote-Include はユーザーが定義した装備セットの中からその状況にあう最適なものを自動的に選択してくれる。
ちなみに Manafont は魔力の泉のこと。

でも、どういうアルゴリズムでどの装備セットが選ばれるのか良く分からない。sets.precast.FC と sets.precast.FC.Cure の両方が存在していると競合しないのかとか気になる。なので調べてみた。なお、language = english とする。



1.基本となるsets

基本となるsetsは以下のものとなる。Mote-Include.luaの108行目で定義されている。
-- Sub-tables within the sets table that we expect to exist, and are annoying to have to
-- define within each individual job file. We can define them here to make sure we don't
-- have to check for existence. The job file should be including this before defining
-- any sets, so any changes it makes will override these anyway.

sets.precast = {}
sets.precast.FC = {}
sets.precast.JA = {}
sets.precast.WS = {}
sets.precast.RA = {}
sets.midcast = {}
sets.midcast.RA = {}
sets.midcast.Pet = {}
sets.idle = {}
sets.resting = {}
sets.engaged = {}
sets.defense = {}
sets.buff = {}

上記の sets の下に新しく”枝”を伸ばして装備セットを定義していく。
これ以外にも、Mote-TreasureHunter.lua では sets.TreasureHunter が使われている。



2.precastでの選択

Mote-Include.lua の get_precast_set()関数の中で装備セットの選択が行われる。
下記のコードの通り、プレイヤーが実行しようとしているアクションが魔法であれば FC の枝が選ばれ、WSであれば WS の枝が選ばれ、それ以外のアビリティであれば JA の枝が選ばれる。
local cat

if spell.action_type == 'Magic' then
    cat = 'FC'  -- sets.precast.FC
elseif spell.action_type == 'Ability' then
    if spell.type == 'WeaponSkill' then
        cat = 'WS' -- sets.precast.WS
    elseif spell.type == 'JobAbility' then
        cat = 'JA' -- sets.precast.JA
    else
        -- Allow fallback to .JA table if spell.type isn't found, for all non-weaponskill abilities.
        cat = (sets.precast[spell.type] and spell.type) or 'JA' -- ex. sets.precast.PetCommand
    end
end


下から3行目のコードは、ペットコマンドなど特殊なアビリティの場合の処理である。その場合、sets.precast.PetCommand が定義されていればそれが装備セットとして選ばれる。
以下は、res\job_abilities.lua から抜き出したものである。type で設定されている文字列を sets.precast の下の枝の名前として使うことができる。つまり、sets.precast.PetCommand だけでなく sets.precast.Samba とか sets.precast.Rune とかも名前として有効。

    [16] = {id=16,en="Mighty Strikes",ja="マイティストライク",prefix="/jobability",type="JobAbility"},
    [68] = {id=68,en="Super Jump",ja="スーパージャンプ",prefix="/jobability",type="JobAbility"},
    [69] = {id=69,en="Fight",ja="たたかえ",prefix="/pet",type="PetCommand"},
    [98] = {id=98,en="Fighter's Roll",ja="ファイターズロール",prefix="/jobability",type="CorsairRoll"},

    [131] = {id=131,en="Light Shot",ja="ライトショット",prefix="/jobability",type="CorsairShot"},
    [184] = {id=184,en="Drain Samba",ja="ドレインサンバ",prefix="/jobability",type="Samba"},
    [190] = {id=190,en="Curing Waltz",ja="ケアルワルツ",prefix="/jobability",type="Waltz"},
    [196] = {id=196,en="Spectral Jig",ja="スペクトラルジグ",prefix="/jobability",type="Jig"},
    [201] = {id=201,en="Quickstep",ja="クイックステップ",prefix="/jobability",type="Step"},
    [205] = {id=205,en="Desperate Flourish",ja="D.フラリッシュ",prefix="/jobability",type="Flourish1"},
    [206] = {id=206,en="Reverse Flourish",ja="R.フラリッシュ",prefix="/jobability",type="Flourish2"},
    [215] = {id=215,en="Penury",ja="簡素清貧の章",prefix="/jobability",type="Scholar"},
    [358] = {id=358,en="Ignis",ja="イグニス",prefix="/jobability",type="Rune"},
    [371] = {id=371,en="Valiance",ja="ヴァリエンス",prefix="/jobability",type="Ward"},
    [372] = {id=372,en="Gambit",ja="ガンビット",prefix="/jobability",type="Effusion"},
    [514] = {id=514,en="Shining Ruby",ja="ルビーの輝き",prefix="/pet",type="BloodPactWard"},
    [516] = {id=516,en="Meteorite",ja="プチメテオ",prefix="/pet",type="BloodPactRage"},
    [676] = {id=676,en="Dream Flower",ja="夢想花",prefix="/pet",type="Monster"},



3.パンくずリスト

たとえば、sets.precast.FC を装備セットとして選んだ時、Mote-Include はパンくずリスト(breadcrumbs)を残す。
mote_vars.set_breadcrumbs:append('sets')
mote_vars.set_breadcrumbs:append('precast')

mote_vars.set_breadcrumbs:append(cat)



4.さらに下の枝

ユーザーがケアル魔法を唱えようとしたとき、デフォルトでは sets.precast.FC が選ばれるが、もしも sets.precast.FC.Cure が定義されているならば sets.precast.FC.Cure が選ばれる。Cure は spell_maps で定義されている。

    spell_maps = {     ['Cure']='Cure',['Cure II']='Cure',['Cure III']='Cure'

上記のような感じで Mote-Mappings.lua の中で定義されている。ケアル以外にも
['Poisona']='StatusRemoval',['Paralyna']='StatusRemoval'
['Barfire']='BarElement',['Barstone']='BarElement'
['Protect']='Protect',['Protect II']='Protect',['Protect III']='Protect'

こんな感じでいろいろ spellMap が定義されている。
(新魔法が実装された場合、Mote-Mappings.lua を直接修正するか、あるいは、ユーザー関数 job_get_spell_map() で対応する必要がある)

例えば、プロテスII を唱えようとしたとき sets.precast.FC.Protect が定義されていればそれが選ばれる。



spellMap が選ばれるコードは以下のもの。
-- Simple utility function to handle a portion of the equipment set determination.
-- It attempts to select a sub-table of the provided equipment set based on the
-- standard search order of custom class, spell name, and spell map.
-- If no such set is found, it returns the original base set (equipSet) provided.

function get_named_set(equipSet, spell, spellMap)
    if equipSet then
        if classes.CustomClass and equipSet[classes.CustomClass] then
            mote_vars.set_breadcrumbs:append(classes.CustomClass)
            return equipSet[classes.CustomClass]
        elseif equipSet[spell.english] then -- ex. sets.precast.FC['Cure V']
            mote_vars.set_breadcrumbs:append(spell.english)
            return equipSet[spell.english]
        elseif spellMap and equipSet[spellMap] then
            mote_vars.set_breadcrumbs:append(spellMap)
            return equipSet[spellMap]
        else
            return equipSet
        end
    end
end
もしも、sets.precast.FC['Cure V'] が定義されている場合、sets.precast.FC.Cure よりも優先して選ばれる。それは上記のコードの通りである。英語フォーラムに投稿されていたものであるが、獣使いの場合、
sets.precast.PetCommand['Spur'] = {feet="Ferine Ocreae +2"}
というゆう風にもできる。Spurは「きばれ」。

個別の魔法名やアビリティ名よりも優先されるのが CustomClassである。これはユーザーが自分で設定する変数値。 英語フォーラムに例があった
function job_post_precast(spell, action, spellMap, eventArgs)
    if player.hpp < 51 then
        classes.CustomClass = "Breath"
    end
end
こんな風にして、ヒールブレス用の装備セットを優先させている。
ユーザーがディアを唱えたとき、sets.precast.FC.Breath が定義されていれば選ばれる。



5.別の選択肢

もしも、sets.precast.FC.Cure も sets.precast.FC['Cure V'] も sets.precast.FC.Breath もユーザーが定義していない場合、その他の選択肢が候補となる。

spell.skill("Healing Magic"、"Enhancing Magic"、"Ninjutsu"など魔法スキルのこと)
spell.type("WhiteMagic"、"BlackMagic"、"SummonerPact"、"Ninjutsu"、
                    "BardSong"、"BlueMagic"、"Trust"など魔法の種類)
の2つが候補。たとえば、
                     sets.precast.FC["Healing Magic"]  -- spell.skill
                     sets.precast.FC["WhiteMagic"] -- spell.type
など。ただし language が japanese の場合は spell.skill の方は日本語で指定する必要がある。

spell.skill と spell.type を選択するコードは以下。注目すべきは最後に get_named_set() を再度呼び出していること。つまり、sets.precast.FC["Healing Magic"].Cure というのも装備セットの名前としては有効。


-- Select the equipment set to equip from a given starting table, based on standard
-- selection order: custom class, spell name, spell map, spell skill, and spell type.
-- Spell skill and spell type may further refine their selections based on

-- custom class, spell name and spell map.
function select_specific_set(equipSet, spell, spellMap)
    -- Take the determined base equipment set and try to get the simple naming extensions that
    -- may apply to it (class, spell name, spell map).

    local namedSet = get_named_set(equipSet, spell, spellMap)
   
    -- If no simple naming sub-tables were found, and we simply got back the original equip set,
    -- check for spell.skill and spell.type, then check the simple naming extensions again.

    if namedSet == equipSet then
        if spell.skill and equipSet[spell.skill] and not classes.SkipSkillCheck then
            namedSet = equipSet[spell.skill]
            mote_vars.set_breadcrumbs:append(spell.skill)
        elseif spell.type and equipSet[spell.type] then
            namedSet = equipSet[spell.type]
            mote_vars.set_breadcrumbs:append(spell.type)
        else
            return equipSet
        end
       
        namedSet = get_named_set(namedSet, spell, spellMap)
    end
    return namedSet or equipSet
end



6.モード

Mote-Include ではモードが定義されている。
モード変更用のキーバインド設定がMote-Globals.luaにある。
-- Function to bind GearSwap binds when loading a GS script.
function global_on_load()
send_command('bind f9 gs c cycle OffenseMode')
send_command('bind ^f9 gs c cycle HybridMode')
send_command('bind !f9 gs c cycle RangedMode')
send_command('bind @f9 gs c cycle WeaponskillMode')
send_command('bind f10 gs c set DefenseMode Physical')
send_command('bind ^f10 gs c cycle PhysicalDefenseMode')
send_command('bind !f10 gs c toggle Kiting')
send_command('bind f11 gs c set DefenseMode Magical')
send_command('bind ^f11 gs c cycle CastingMode')
send_command('bind f12 gs c update user')
send_command('bind ^f12 gs c cycle IdleMode')
send_command('bind !f12 gs c reset DefenseMode')

send_command('bind ^- gs c toggle selectnpctargets')
send_command('bind ^= gs c cycle pctargetmode')
end
各モードの内容は user_setup()関数でユーザー自身が定義する。
以下は BLM.lua の例。
function user_setup()
    state.OffenseMode:options('None', 'Normal')
    state.CastingMode:options('Normal', 'Resistant', 'Proc')
    state.IdleMode:options('Normal', 'PDT') -- Physical Damage taken
Resistant は魔命特化、Proc はアビセアなどでの弱点用。PDT は物理防御。
プレイ中に Ctrl-F11 で CastingMode を変えることができる。
sets.midcast['Elemental Magic'].Resistant
sets.midcast['Elemental Magic'].Proc
上記のように定義しておけば、そのときのモードに合わせて自動的に選択される。









0 件のコメント:

コメントを投稿