2007年 05月 06日

Ragnarok Online のホムンクルス AI

Lua 云々はこれのためにやっていたやつです。
公式配布のもの (ROのインストールディレクトリの AI 以下) は最小限の機能が最小限の実装で書かれていて、そのままだと読みにくく、書きかえにくい。

なので、とりあえずデフォルトのAIの機能を移植するかたちで、書きやすように OOP 化しはじめてみた ( http://lab.lowreal.net/trac/browser/c/ro/AI/ )

デフォルトの Util.lua にある List テーブルがなぜかクラスではないので List.lua として分離し、ruby っぽいメソッドをいくつか追加した。

l = List.new(1, 2, 3)
l:join() --> "1, 2, 3"

l1 = List.new(4, 5, 6)
l2 = l + l1
l2:map(function (i)
    return i * i
end) --> 1, 4, 9, 16, 25, 36

クラスの実装は http://subtech.g.hatena.ne.jp/cho45/20070502/1178092846 のまま。


GetDistance 系はダサいので、Actor クラスを作ってラップしてある (Actor.lua)。Actor クラスはモンスターやホムやプレイヤーに対して使えるクラス。

a1 = Actor.new(id)
a2 = Actor.new(other_id)

a1:distanceFrom(a2) > 3
a1:isInSight(a2) --> a2 が 20 セル以内にいるとき true
a1:isInAttackSight(a2) --> a2 が攻撃可能な範囲にいるとき true (今は単に 1 セル以内)

a1:isStand() --> a1 が立っているとき true

これによって GetV を使わなくてすむはず。定数を何回も書くのがめんどいのでちょっと楽かなぁと思う。


Homun クラス (Homun.lua) は飼っているホムに使うクラス。Actor のサブクラスになっていて、Actor のメソッドはよべる。

h = Homun.new(myid)
h:owner() --> オーナーキャラ (つまり操作している自分のキャラ) を Actor インスタンスで取得
h:move(x, y) --> x, y に移動
h:attack(target) --> target を攻撃 (attack できる範囲にはいっていないと何もおきないと思う)

スキル使うのはこれから実装する (AIばっかり書いててまだスキルがとれてない)


RO からは AI.lua が呼びだされる。こいつにはデバッグメッセージの出力と、本体でエラーをはいたときに RO のほうに伝達しないようにしてる (RO に伝達すると、ダイアログが表示されまくって Alt-F4 するしかない。さすが! 重力クオリティ!) AI.lua は Main.lua をロードして、Main 関数を実行する。

Main.lua には Main 関数と HogeAI クラスと reload 関数が定義されてる。

Main 関数では HogeAI クラスをインスタンス化して、RO から呼びだしがくるたびに、インスタンス化した AI クラスの act メソッドを呼びだしている。CurrentAI とかいうグローバル変数に突っ込んでいるのは、そのうち切りかえとかできたらなぁとか考えているからだけど、実装できるか謎い。

HogeAI は今つくってる劣化デフォルトAI で、やってることはデフォルト AI とそんな違いはないはず (実装してないのがいくつかある)。デフォルト AI の処理をとりあえず移植したら DefaultAI クラスにでもして、それのサブクラスを作ったらいいかなぁとか思ったけど、まだやってなくてわからない。

Try と xpcall

xpcall とかいう関数ふたつとってエラーキャッチする関数をみのがしてた!!
Try をつかいつづけるか悩む

RO AI