ホムンクルスAI

主にケミWikiに自分が書いてたやつの再編と拡張。多分あっちは誰も見てないし。

注意

  • ROクライアントでは Lua 標準の剰余演算子 % は使えない。
    代わりに math.mod を使うこと。
    C = A % B
    C = math.mod(A,B)

  • 2011年10月ごろのパッチから Move 命令の挙動が変更された模様。
    モンスターなどのオブジェクトのある座標に Move 命令を出しても動かない。
    対応策として直前の座標を保持しておき、そこへ移動するように指示するなどが必要。
    また、この変更によりモンスターなどが密集した場所にはホムンクルスがうまく動けない。

文字コード

韓国語EUC(ハングル)で記述されている。
一応、ASCIIコードでの下位互換があるためシフトJISやutf-8 などで書いても動くが
予想外のエラーを引き起こす可能性があるので日本語EUCで書いたほうがよいだろう。

また、TraceAI 関数でデバッグ文字列を出力すると韓国語EUCの日時文字列が先頭行につく。
このため日本語で文字列を送ると複数の文字コードが混在してしまうため
TraceAI 関数に送る文字列の文字コードは半角英数字を使ったほうがよい。
あえて全角文字を送りたいならば独自のデバッグ関数を作るべき。

コマンド

/hoai
AI切り替えコマンド。
インストールフォルダ以下の AI/AI.lua と AI/USER_AI/AI.lua を切り替える。
USER_AIフォルダとそれ以下に AI.lua が必要。
/traceai
デバッグログ出力のON/OFF。
TraceAI()関数に送られた文字列をインストールフォルダの TraceAI.txt に出力する。

デフォルトAI機能

AI.lua で定義。

定数

定数名取得する情報対応する命令
(Const.luaで定義)
IDLE_ST0待機-
FOLLOW_ST1追従-
CHASE_ST2追跡-
ATTACK_ST3攻撃-
MOVE_CMD_ST4移動命令MOVE_CMD
STOP_CMD_ST5停止命令STOP_CMD
ATTACK_OBJECT_CMD_ST6対象攻撃ATTACK_OBJECT_CMD
ATTACK_AREA_CMD_ST7対地攻撃ATTACK_AREA_CMD
PATROL_CMD_ST8パトロール命令PATROL_CMD
HOLD_CMD_ST9ホールド命令HOLD_CMD
SKILL_OBJECT_CMD_ST10対象スキル命令SKILL_OBJECT_CMD
SKILL_AREA_CMD_ST11対地スキル命令SKILL_AREA_CMD
FOLLOW_CMD_ST12追跡命令(非攻撃/攻撃状態切り替え)FOLLOW_CMD

変数

変数名初期値意味
MyStateIDLE_ST状態ID
MyEnemy0ホムンクルスの標的オブジェクトID
MyDestX0ホムンクルスの移動先X座標
MyDestY0ホムンクルスの移動先Y座標
MyPatrolX0ホムンクルスのパトロールX座標
MyPatrolY0ホムンクルスのパトロールY座標
ResCmdListList.new()手動命令の予約リスト
MyID0ホムンクルス自身のID
MySkill0ホムンクルスの使うスキルID
MySkillLevel0ホムンクルスの使うスキルレベル

関数

関数機能
内部関数TraceAI (string)文字列を TraceAI.txt ファイルに出力。
先頭に時間も付くが翻訳されておらず「2011鰍 12杉 31析 12獣 30歳 59段」のようになる
MoveToOwner (homun_id)ホムンクルスを主人の近くに移動する。最短距離ではなく周囲のどこかに移動する
Move (homun_id,x,y)ホムンクルスを指定座標に移動
Attack (homun_id,id)ホムンクルスからオブジェクトIDを攻撃させる
GetV (V_,id)指定オブジェクトIDの各種情報を取得する
GetV (V_TYPE,id)指定オブジェクトIDの情報を取得するはずだが、使われておらずオブジェクトIDがそのまま返る
GetV (V_HOMUNTYPE,id)指定オブジェクトIDのホムンクルスタイプIDを取得する。
また、ホムンクルス以外のオブジェクトIDを指定すると
キャラクターの職業やモンスターの種類などを取得する。
GetActors ()クライアント画面内のオブジェクトIDを取得しリストで返す
GetTick ()時間を取得(ミリ秒単位)
GetMsg (homun_id)クライアントから送られた手動命令を取得
GetResMsg (homun_id)クライアントから送られた手動命令(+シフトキー)を取得
SkillObject (homun_id,level,skill,target)ホムンクルスからオブジェクトIDにスキルを使わせる
SkillGround (homun_id,level,skill,x,y)ホムンクルスから指定座標にスキルを使わせる(無効)
IsMonster (id)オブジェクトIDが攻撃可能か?可能なら 1、不可なら 0 を取得(真偽値ではない)
メイン関数AI (myid)クライアントに呼び出されるメイン関数
myid にホムンクルス自身のオブジェクトIDが入る
命令処理ProcessCommand (msg)手動命令振り分け
OnMOVE_CMD (x,y)移動命令
OnSTOP_CMD ()停止命令<無効>
OnATTACK_OBJECT_CMD (id)対象攻撃命令
OnATTACK_AREA_CMD (x,y)範囲攻撃命令<無効>
OnPATROL_CMD (x,y)パトロール命令。ホムンクルスの現在地をPatrolX,Yに、
指定座標をPatrolX,Yにセットしパトロール状態に移行
OnHOLD_CMD ()ホールド命令。敵、移動先リセット
OnSKILL_OBJECT_CMD (level,skill,id)対象スキル命令
OnSKILL_AREA_CMD (level,skill,x,y)範囲スキル命令<無効>
OnFOLLOW_CMD ()手動追従(非攻撃)命令
状態遷移
(自動)
OnIDLE_ST ()待機状態
OnFOLLOW_ST ()追従状態
OnCHASE_ST ()攻撃対象の追尾状態
OnATTACK_ST ()攻撃状態
状態遷移
(手動)
OnMOVE_CMD_ST ()手動移動状態
OnSTOP_CMD_ST ()停止状態
OnATTACK_OBJECT_CMD_ST ()対象攻撃状態
OnATTACK_AREA_CMD_ST ()範囲攻撃状態
OnPATROL_CMD_ST ()パトロール状態。座標間を行き来して敵を発見したら追跡状態へ
OnHOLD_CMD_ST ()ホールド状態
OnSKILL_OBJECT_CMD_ST ()対象スキル状態
OnSKILL_AREA_CMD_ST ()範囲スキル状態
OnFOLLOW_CMD_ST ()手動追従状態
索敵GetOwnerEnemy (myid)主人を標的にしているもっとも近いオブジェクトIDを取得
GetMyEnemy (myid)索敵関数振り分け。
GetMyEnemyA (myid)索敵関数A。ホムを標的にしているもっとも近いオブジェクトIDを取得
GetMyEnemyB (myid)索敵関数B。攻撃可能でもっとも近いオブジェクトIDを取得。
横殴りになるので使うべきではない。
ユーティリティ
Util.lua
で定義
List.new ()リストテーブル作成して返す
List.pushleft (list, value)先頭に要素を追加
List.pushright (list, value)末尾に要素を追加
List.popleft (list)先頭から要素を取り出す
List.popright (list)末尾から要素を取り出す
List.clear (list)リストテーブルをクリアする
List.size (list)リストテーブルの要素数を返す
GetDistance (x1,y1,x2,y2)2点間の距離を返す
GetDistance2 (id1, id2)2つのオブジェクトID間の距離を返す
GetOwnerPosition (id)主人の座標を返す
GetDistanceFromOwner (id)主人とオブジェクトIDの距離を返す
IsOutOfSight (id1,id2)視界内の判定。実際には2つのオブジェクト間の距離が20以内かの判定
IsInAttackSight (id1,id2)id1の攻撃(スキル)射程内かの判定

状態遷移

状態概要初期動作継続動作
IDLE_ST
待機
敵待ち受け-敵がいれば標的をセットし追跡状態に。
敵がおらず主人と離れた場合は自動追従状態に
FOLLOW_ST
自動追従
主人を追従-主人に近づく。主人に近づいたら待機状態に移行
CHASE_ST
追跡
敵追跡-敵が離れていれば追跡する。
敵を見失ったら待機状態に。
敵が攻撃射程にいれば攻撃状態に。
ATTACK_ST
攻撃
敵攻撃-敵が近くにいれば攻撃し、
スキルが指定されていればスキルで攻撃する。
敵が離れていれば追尾状態に。
敵が死んだり見失った場合は待機状態に。
MOVE_CMD_ST
手動移動
目的地に移動指定座標とホムの現在地が同じなら何もしない。
違うなら標的リセットし指定座標に移動し移動状態に。
ホムが移動先に着けば待機状態に、
そうでなければ状態の維持
STOP_CMD_ST
停止
行動中断し
待機状態に
標的・移動先・スキルをリセットし待機状態に何もしない
ATTACK_OBJECT_CMD_ST
対象攻撃
通常攻撃移動先・スキルをリセットし追跡状態に何もしない
ATTACK_AREA_CMD_ST
対地攻撃
目的地に移動し
対地攻撃
標的をリセットし指定座標を移動先にセットし範囲攻撃状態に敵がいれば標的をセットし追跡状態に
移動先に着くと
待機状態に(ただし範囲攻撃は未定義)
PATROL_CMD_ST
パトロール
2点間移動し
敵待ち受け
指定座標を移動先に、ホムの現在地をパトロール地にセットしパトロール状態に敵がいれば標的をセットし追跡状態に
敵がいなければ2点間を行き来する
HOLD_CMD_ST
ホールド
移動停止し
敵待ち受け
敵・移動先リセットしホールド状態に攻撃射程内に敵がいれば攻撃、
そうでなければその場で動かない
SKILL_OBJECT_CMD_ST
対象スキル
スキル攻撃標的とスキルをセットし追跡状態に何もしない
SKILL_AREA_CMD_ST
対地スキル
目的地に移動し
対地スキル
移動先とスキルをセットし範囲スキル状態に移動先に着くと範囲スキルを使用し
待機状態に(ただし範囲スキルは未定義)
FOLLOW_CMD_ST
非攻撃追従待機状態・手動追跡状態を入れ換え主人から離れていれば近づき、近いなら何もしない

トリガー

トリガー、つまりAIに何かしらの行動を起こさせるスイッチ

ALT+T
GetMsg に {FOLLOW_CMD} のテーブル形式で取得できる。
ALT+敵ダブルクリック
GetMsg に {ATTACK_CMD,敵のオブジェクトID} のテーブル形式で取得できる。
ALT+SHIFT+対象ダブルクリック
GetResMsg に {ATTACK_CMD,対象のオブジェクトID} のテーブル形式で取得できる。
敵に限らず一般フィールドのプレイヤーなども取得できる。
ALT+地面クリック
GetMsg に {MOVE_CMD,X座標,Y座標} のテーブル形式で取得できる。
ALT+SHIFT+地面クリック
GetResMsg に {MOVE_CMD,X座標,Y座標} のテーブル形式で取得できる。
対象指定スキル使用
カプリス、ムーンライト、SBR44の使用時には
GetMsg に {SKILL_OBJECT_CMD,スキルレベル、対象のオブジェクトID} の形式で取得できる。
それ以外のスキルを使っても GetMsg は無反応。
主人の立ち/座り
GetV(V_MOTION,主人のオブジェクトID) で取得できる。
他のモーションも拾えるが戦闘モーションくらいしか使い道はなかろう。
  • できそうでできないトリガー
    • SHIFT+ALT+T
    • SHIFT+対象指定スキル
    • 一般フィールドでALT+プレイヤーダブルクリック
    • 対象を指定する必要のないスキル(ディフェンス、フリットムーブ、治癒の手など)
    • エサやりを感知

オブジェクトとは

  • プレイヤーやホムンクルス、ペット、カプラ、看板、ワープポイントといったゲーム内に設置された物体全般を指す。

  • 大きく分けてプレイヤーの操作するプレイヤーキャラクター(PC)と
    操作できないノンプレイヤーキャラクター(NPC)に別れる。
    ホムンクルスは間接的に操作できるが、NPCに分類される。

  • オブジェクトはそれぞれが異なる識別番号(ここではオブジェクトIDと呼ぶ)を持ち、
    これがオブジェクトを区別する印となる。

オブジェクトID

  • NPCは1〜100000のID、PCは100001 以上の他と重複しないユニークなIDが割り振られる。
    • NPCはIDが一定していない。
      同じマップに常駐するモンスターNPCのIDはある程度一定していることもあるが、
      古木の枝やバイオプラントなどで誕生させたモンスターのIDは呼び出すごとに違う。
    • PCはアカウントごとにIDが固定されている。
      PCはログアウトやキャラクターチェンジをしても同じIDになる。
      つまりキャラクターを変えてもそれぞれを見分ける手段は職業くらいしかないがそれも完璧ではない。
  • NPC(モンスター、ホムンクルスなど)は死亡すると「100000 - 現在のID」から算出される新たな死体オブジェクトを生成する。
    同時に元のNPCが消滅して死体と入れ替わる。
    例)ID 53443 のモンスターが死亡すると ID 46557 の死体オブジェクトと入れ替わる
    死体オブジェクトは倒れ込んだり半透明になっていくような死亡モーション(MOTION_DEAD)を起こし、数秒後に消滅する。
    これがモンスターを倒した後に行われる処理だ。
    プレイヤーは死亡してもモーションが死亡となるだけでIDは変わらない。

  • IDを取得できないオブジェクト
    プレイヤーが攻撃できるトラップやアイスウォールなどのIDは取得できない。
    そのため、ホムンクルスには攻撃できない
    攻撃命令をしても何故か主人が近づいたり、攻撃を始めるバグがある
    ドロップしたアイテムにもIDはあるようだがこれも取得できない。

  • IDの取得方法
    • プレイヤーの呼び出したホムンクルスのIDはメイン関数 AI(myid) の第一引数に与えられている。

    • ホムンクルスの主人のIDは GetV(V_OWNER,id) 関数で取得できるが、
      現在のところプレイヤー以外の主人のIDは受け取れない。

    • 画面内にあるオブジェクトIDは GetActors 関数で取得できる。

    • ホム、主人、モンスターなどが標的にしているオブジェクトIDは GetV(V_TARGET,id) 関数で取得できる。

オブジェクトの識別

  • オブジェクトID とホムタイプ IsMonster を踏まえた上での識別
ID種類IsMonHOMUNTYPE補足
PC
10万より上
(固定値)
プレイヤー0(1)職業の固有値シーズモードでは
自分以外のプレイヤーのIsMonsterが1
NPC
10万以下
(変動値)
ホム0(1)ホム種類の固有値シーズモードでは
自分のホム以外のIsMonsterが1
ペット0通常モンスターの値
通常モンスター1通常モンスターの値
死亡モンスター1通常モンスターの値(100000 - 死んだモンスターID)のIDを持つ。
主にMOTION_DEADを出す
バイオプラント1専用の値バイオプラント専用のモンスター
スフィアーマイン1通常モンスターの値通常モンスターとマインを区別できない
その他0各NPCに応じた値人、看板、ワープポイント他

ホムタイプ HOMUNTYPE


GetV(V_HOMUNTYPE,id) で取得できる値は
id がホムンクルスなら各種ホムンクルスを示す値を返すが、
それ以外のidを与えた場合はモンスターや看板、ワープポイント、カプラ
各種プレイヤーの職業に応じた値なども返す
ただし、ホムンクルスの種類の値とプレイヤーの職業の値が一部重なっているため、
NPCとPCの区別をしてから判定する必要がある。

バイオプラントで召喚される植物モンスターは
通常のモンスターとは HOMUNTYPE が違うのでこれを見て攻撃しないようにもできる。

-------------------------------------------
-- バイオプラント召喚モンスターのHOMUNTYPEかどうか
-------------------------------------------
function IsBioPlantType(type)
    if (type==1589 or type==1579 or type==1575 or type==1555 or type==1590) then
        return true
    end
    return false
end

攻撃の可否


IsMonster(id) はその関数名とは違い
対象が「モンスターかどうか」ではなくホムが「攻撃できるか否か」である
ペットやNPCの人物などは攻撃できないので 0 を返す。
通常はモンスターだけにこの値が 1 となるが、
GvG や PvP のシーズモードでは他プレイヤーや他人のホムに対しても 1 を返す。
バイオプラントやスフィアーマインでの召喚モンスターも攻撃できるために 1 だ。
当然ながら、ホムンクルス自身と主人は攻撃できない。

  • クエストやイベントで設置されているモンスターにも IsMonster が 1を返す。
    しかし攻撃することができず、ホムンクルス側からクエスト用とは区別できない。

テーブルの値の取得

for i,v in ipairs(table) do
    table[i] == v -- table[i]とvは等しい
end

このループは table = {[1]="A", [2]="B"} のような
連続したキーが入っていると想定している。
このため table = {[1]="A", [2]="B", [5]="E"} のように間が空くと
それ以降は取得せずに 2 番目で終了してしまう。
また、キーは 0 ではなく 1 から順に取得する。
全てを取得したいのなら pairs を使うべき。

for k,v in pairs(table) do
    table[k] == v -- table[k]とvは等しい
end

このループはすべてのキーと対応する値を取得するが
これらは順番に取得するとは限らない。

できる/わかること

主人の 現在のHP/最大HP/現在のSP/最大SP
ホム自身の 現在のHP/最大HP/現在のSP/最大SP
画面内のオブジェクトの狙っている標的
画面内のオブジェクトのモーション
画面内のオブジェクトの座標
PCかNPCかどうか
他プレイヤーの記憶

できない/わからないこと

パーティメンバー、ギルドメンバー
自分や主人のステータス
現在いるマップ
他のホムの主人が誰か
他のケミの従えているホムがどれか
他人の 現在のHP/最大HP/現在のSP/最大SP
モンスターの 現在のHP/最大HP/現在のSP/最大SP
使っているスキルが何か
現在かかっている支援スキルが何か
攻撃が当ったかどうか
攻撃を受けたかどうか
その場所に移動できるかどうか
対象の間に障害物があるかどうか
満腹度
カプリス、ムーンライト以外のスキル命令


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規新規下位 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-05-24 (木) 17:56:16 (1912d)