1- 101- 201- 301- 401- 501- 601- 701- 801- 901-

ホムンクルスのAIを語るスレ その4

1(○口○*)さん :06/03/24 18:48
ここはアルケミストのホムンクルスAIについて語るスレです。

■前スレ
ホムンクルスのAIを語るスレ その3
http://enif.mmobbs.com/test/read.cgi/livero/1142535070/

■関連スレ
ホムンクルスAIについての雑談・要望スレ
http://enif.mmobbs.com/test/read.cgi/livero/1142513331/
アルケミスト・クリエイター情報交換スレ第68巻
http://gemma.mmobbs.com/test/read.cgi/ragnarok/1143026955/
アルケミスレテンプレサイト
http://cgi.f31.aaacafe.ne.jp/~alchemi/pukiwiki.php?

2テンプレつづき :06/03/24 18:49
■AI配布サイト
▼初心者向け
くま○〜@ガルムのAI 通称:くまAI
ttp://www.kmzw.jp/nb/ai/
▼中級者向け
0-material 通称:ぜろまてAI
ttp://www.kogarashi.jp/0-material/
Winter's Tale 通称:韓国AI
ttp://www.sgv417.jp/~winter/
▼上級者向け
工体研究所 通称:工体AI
ttp://blog.livedoor.jp/aidev/

■LUA関連サイト
LUA日本語リファレンス
ttp://www.uri.sakura.ne.jp/~cosmic/yuno/lab/lua5_manual_ja.html
LUAの参考書のオンライン版(英語)
ttp://www.lua.org/pil/
luaのFAQ
ttp://garage.sakura.ne.jp/yuno/html/lua5_faq_ja.html
luaユーザー会Wiki(英語)
ttp://lua-users.org/wiki/
lua日本語パッチ
ttp://www.water.sannet.ne.jp/sowwa/
2chプログラム技術板 プログラミング言語 Lua  その2
http://pc8.2ch.net/test/read.cgi/tech/1063711237/
LuaEclipse(英語)
ttp://www.ideais.com.br/luaeclipse/

3(○口○*)さん :06/03/24 19:59
>>1
乙〜

4(○口○*)さん :06/03/24 20:46
前スレはもう埋まりそうなのでこっちに

ALT+右クリックで、特定の順番でホムを移動させるのをスイッチにして
アクティブ・ノンアクティブの切り替えをやってみた。

前スレ279氏がやってる一時的な護衛対象設定も組み込んでます。

-- 定数
COMMAND_LIMIT      = 4000    -- 入力制限時間(ミリ秒)
-- 変数
Attack_Mode        = 0      -- 行動設定初期値(0:ノンアクティブ 1:アクティブ)
Command_Type      = 0      -- コマンド種別
Command_Count      = 0      -- コマンド入力カウンタ
Command_Conplete    = false    -- コマンド完了フラグ
Command_Time      = 0      -- 入力制限時間

Master_Change_X      = 0      -- マスター一時入れ替えコマンドの基準X座標
Master_Change_Y      = 0      -- マスター一時入れ替えコマンドの基準Y座標
Follow_Target      = 1      -- マスター一時入れ替え時の追尾対象(0:オーナー 1:一時マスター)

MyMASTER        = MyOWNER  -- 現在のマスター

------------------------------------------
-- ステップコマンド
------------------------------------------
function StepCommand (myX, myY, ownerX, ownerY)

  -- 入力時間を超過した場合、コマンドをリセットする
  if (Command_Type ~= 0 and Command_Time < GetTick()) then
    Command_Type = 0
    Command_Count = 0
    TraceAI ("StepCommand : Command_TimeOut")
  end

  local cnt = Command_Count

5続き :06/03/24 20:46
  -----------------------------------------
  --- アクティブモード
  -----------------------------------------
  --- □A□
  --- □主□
  --- @□B
  --- ALT+右クリックで、@→A→Bの順にホムを移動させると
  --- アクティブ化します。
  --- アクティブ化に成功した際、ホムは自動で@の位置に移動。
  
  if (myX == ownerX - 1 and myY == ownerY - 1) then  -- @
    if (Command_Type == 0) then
      Command_Type = 1
      Command_Count = 1
      Command_Time = GetTick() + COMMAND_LIMIT
    end
  end
  if (myX == ownerX and myY == ownerY + 1) then    -- A
    if (Command_Type == 1 and Command_Count == 1) then
      Command_Count = 2
    end
  end
  if (myX == ownerX + 1 and myY == ownerY - 1) then  -- B
    if (Command_Type == 1 and Command_Count == 2) then
      Attack_Mode = 1                  -- アクティブ化
      Command_Conplete = true
      Command_Count = 0
      TraceAI ("StepCommand : Mode_Active")
    end
  end

6続き2 :06/03/24 20:47
  -----------------------------------------
  --- 非アクティブモード
  -----------------------------------------
  --- @□B
  --- □自□
  --- □A□
  --- ALT+右クリックで、@→A→Bの順にホムを移動させると
  --- 非アクティブ化します。
  --- 非アクティブ化に成功した際、ホムは自動で@の位置に移動。
  if (myX == ownerX - 1 and myY == ownerY + 1) then  -- @
    if (Command_Type == 0) then
      Command_Type = 2
      Command_Count = 1
      Command_Time = GetTick() + COMMAND_LIMIT
    end
  end
  if (myX == ownerX and myY == ownerY - 1) then    -- A
    if (Command_Type == 2 and Command_Count == 1) then
      Command_Count = 2
    end
  end
  if (myX == ownerX + 1 and myY == ownerY + 1) then  -- B
    if (Command_Type == 2 and Command_Count == 2) then
      Attack_Mode = 0                  -- 非アクティブ化
      Command_Conplete = true
      Command_Count = 0
      TraceAI ("StepCommand : Mode_NotActive")
    end
  end

7続き3 :06/03/24 20:48
  -----------------------------------------
  -- マスター一時入れ替え
  -----------------------------------------
  --- C□B
  --- □主□
  --- @□A
  --- ALT+右クリックで、@→A→Bの順にホムを移動させると
  --- 中央にいるプレイヤーキャラorホムンクルスを一時的に主人とします。
  --- マスター一時入れ替えに成功した際、ホムは自動で@の位置に移動。
  --- 対象PCが本当の主人から一定距離以上離れるか、直接移動入力で解除されます。
  
  if (Command_Type == 0 and Command_Count == 0) then            -- @
    Master_Change_X = myX
    Master_Change_Y = myY
    Command_Type = 3
    Command_Count = 1
    Command_Time = GetTick() + COMMAND_LIMIT
  end
  if (myX == Master_Change_X + 2 and myY == Master_Change_Y) then      -- A
    if (Command_Type == 3 and Command_Count == 1) then
      Command_Count = 2
    end
  end
  if (myX == Master_Change_X + 2 and myY == Master_Change_Y + 2) then    -- B
    if (Command_Type == 3 and Command_Count == 2) then
      Command_Count = 3
    end
  end
  if (myX == Master_Change_X and myY == Master_Change_Y + 2) then      -- C

8 :06/03/24 20:49
    if (Command_Type == 3 and Command_Count == 3) then
      local actors = GetActors ()
      local chkX,chkY
      for i,v in ipairs(actors) do
        if ( v ~= myid) then
          chkX,chkY = GetV (V_POSITION,v)
          if (chkX == myX + 1 and chkY == myY - 1) then
            if IsPlayer(v) then          -- 対象がプレイヤーキャラの場合
              MyMASTER = v          -- 一時マスターに設定
              TraceAI ("MasterID : "..v)
              break;
            end
          end
        end
      end
      if (MyOWNER ~= MyMASTER) then
        Command_Conplete = true        -- マスター一時入れ替え成功
        Command_Count = 0
        TraceAI ("StepCommand : Master_Change")
      else
        Command_Type = 0          -- 入れ替え対象無し
        Command_Count = 0
      end
    end
  end

  -- コマンド入力を間違えた場合、コマンドをリセットする
  if (Command_Type ~= 0 and cnt == Command_Count) then
    Command_Type = 0
    Command_Count = 0
    TraceAI ("StepCommand : Command_Miss")
  end
end

9(○口○*)さん :06/03/24 20:51
On_MOVE_CMD の最初に以下を追加。
  MyMASTER = MyOWNER  -- 主人をリセット
  
  -- ステップコマンド
  StepCommand (x, y, ownerX, ownerY)


On_IDLE_ST の最後に以下を追加。
  -- ステップコマンド完了時処理
  if (Command_Conplete == true) then
    if (Command_Type == 1) then        -- アクティブ化
      masterX, masterY = GetV (V_POSITION,MyOWNER)  -- 主人の座標を取得
      Move (MyID,masterX - 1,masterY - 1)      -- 主人の南西に移動
      Command_Type = 0
      Command_Conplete = false
    elseif (Command_Type == 2) then      -- 非アクティブ化
      masterX, masterY = GetV (V_POSITION,MyOWNER)  -- 主人の座標を取得
      Move (MyID,masterX - 1,masterY + 1)      -- 主人の北西に移動
      Command_Type = 0
      Command_Conplete = false
    elseif (Command_Type == 3) then      -- マスター一時変換
      Move (MyID,Master_Change_X,Master_Change_Y)  -- コマンド開始位置に移動
      Command_Type = 0
      Master_Change_X = 0
      Master_Change_Y = 0
      Command_Conplete = false
    end
  end

10最後 :06/03/24 20:57
連続投稿制限痛い痛い

GetMyEnemyを以下のように変更
function  GetMyEnemy (myid)
  local result = 0
  -- 索敵モードの切替
  if (Attack_Mode == 0) then
    result = GetMyEnemyA (myid)
  else
    result = GetMyEnemyB (myid)
  end
  return result
end

あと範囲外に出たらリセットとか追尾関連とかあるけど
そこは省略。

切り替えはしたいけど、簡単なスイッチだと間違って切り替えちゃうから・・・
という人にはいいんじゃないかな。うん。

11(○口○*)さん :06/03/24 21:58
擬似マスターは面白いな。
マスターが前に出る必要なくなるから後半はいいかもしれない。

12(○口○*)さん :06/03/24 22:46
まあ工体AIでアクティブ非アクティブ切り替えも擬似マスターも両方あるけどなorz

13(○口○*)さん :06/03/24 23:16
>>4さんのを元に入力部分をちょっと汎用性をあげてみたよ
でもきっと穴があるから誰か埋めて埋めて

ttp://lliorzill.hp.infoseek.co.jp/ai2.html

14(○口○*)さん :06/03/24 23:38
今更だけど、GetVでV_SKILLATTACKRANGEを取得するときの引数って3つなんだな
-- IsInAttackSight:144
GetV(V_SKILLATTACKRANGE,id1,MySkill)

GetVの引数は2つだっていう常識が頭から離れなかったんで、
Lua errorで3つめの引数がおかしいって言われても何のことかわからなかったわ
まぁ、スキルレンジじたい未実装だから関係ないけどねw

1513 :06/03/25 00:34
座標の回転の為の行列間違ってたよorz

164-10 :06/03/25 00:58
ID変わりましたが。

>>13さんありがとう。その手があったかー
拡張性が低いのは分かってたんだけど、思いつくのは
「この書き方であらかじめ何種類かのコマンドを準備しておいて、それぞれ番号振ってConstAreaで機能を割り当てる」
くらいしかなかったので目から鱗。

自分で長々と張っといてあれだけど、試しに導入してみるには面倒な量なのと
マスター云々の辺りも省略してるので
自分とこのAI晒すことにします。
ttp://ww4.enjoy.ne.jp/~to4/ai.html
実はコマンドの入力、結構だるいので参考までに。

17(*○口○)さん :06/03/25 01:00
ホムンクルス用モンスターデータライブラリ
mobdata.lua

配布場所(後日変更の可能性有)
ttp://briefcase.yahoo.co.jp/kulus_project
ttp://proxy.f3.ymdb.yahoofs.jp/bc/44183003_d9ee/bc/mobdata.lua?bc3zBJEBE8CZX1aP

・リヒタルゼンモンスター追加
・ガーディアン3体、エンペリウム追加
・ラフレシア追加(要HIT、FLEEの情報が不明な為0です)
・プラントmob、チンピラ(リヒ)等、その他多数修正

※注意※
現状のmobdata.luaにはID違いの全く同名のモンスターが居ます。
var.2006/03/17 から 蟻の卵、レクイエム
var.2006/03/24 追加 生体ダンジョンBOSSモンスター
未実装データ フォトキャノン4種

ちょっと個人的なことですが、引越し等あるので暫く追加修正はお預けです(´・ω・`)

18(○口○*)さん :06/03/25 01:09
>>14
ぶっちゃけわかってるスキルに関しては擬似関数は作れるけどね。
カプリスはわからんけどムーンライトは視界内だから20か21くらいとしとけばいいか。
そういやスキルのデータまとめようとしてる人いたな。

19(○口○*)さん :06/03/25 02:33
特定のMobが近づいてきたら逃げるっていう動作をさせる場合
やはり攻撃を受けたのを判定して逃げるようにするべきなのかな?

ホムから何セル以内の範囲っていう判定ができればいけそうだけど・・・
その前に指定Mobがたくさんいたらホムがあたふたしそうだなorz

20(○口○*)さん :06/03/25 02:41
>>19

http://enif.mmobbs.com/test/read.cgi/livero/1142535070/242
この辺りが参考になるかと
そして私も引越し、ぜんぜん荷造り終わらない……

21(○口○*)さん :06/03/25 02:56
>>20
それ書いた人だけど、ミスひとつ。
*4のとこ、
- atk = GetMobData(M_V_ATKMAX, id)
+ atk = GetMobData(M_V_ATKMAX, v)
でよろ。

22(○口○*)さん :06/03/25 04:00
前スレで、攻撃回数を数えたかったものですが・・・
結局以下のように、妥協しました。

/**********************************************************/
AttackCounter = 0
MobMotionCount = 0
MobMotion = 0

function OnATTACK_ST ()

                                -- ■▼攻撃回数のカウント ここから▼
      if (MobMotion ~= GetV(V_MOTION,MyEnemy) and MobMotion == MOTION_DAMAGED) then
        AttackCounter = AttackCounter + 1
        MobMotionCount = 0
      elseif (MobMotion == GetV(V_MOTION,MyEnemy) and MobMotion == MOTION_DAMAGED) then
          MobMotionCount = MobMotionCount + 1
        if (MobMotionCount > 3) then
          AttackCounter = AttackCounter + 1
          MobMotionCount = 0
        end
      end
      MobMotion = GetV(V_MOTION,MyEnemy)
                                -- ■▲攻撃回数のカウント ここまで▲
      Attack (MyID,MyEnemy)                -- ■ホムは敵を物理攻撃する

end
/**********************************************************/

ホムの攻撃前後のモーションは全く取れなかったので、
モンスターのモーションが、被弾から他のモーションに変化した回数を数えています。
ただし、被弾モーションの長い敵は、前後の被弾モーションが被ってしまうので
3回以上、被弾モーションが連続したらカウンタをインクリメントしています。

これだと、ぼちぼち実際の攻撃回数が取れます。
問題は、環境によりそうなのと、複数人数で殴ってる時は当てにならないのが・・・

23(○口○*)さん :06/03/25 04:32
前スレの
ttp://enif.mmobbs.com/test/read.cgi/livero/1142535070/998

ミスに気づいたので修正
ttp://www.mmobbs.com/uploader/files/106.zip

24(○口○*)さん :06/03/25 05:37
リーフの緊急回避自動使用だけど
ホムのAIってテレポする毎に変数が全てリセットされるから
飛びまくると緊急回避連打するハメになってあっという間にSP尽きるじゃん?
あれ初回だけ発動時間を微妙に遅らせるといい感じでホム出しっぱで飛びまくれるお。

飛びまくると空腹タイマーが遅れるっぽいのであまりオススメできないけど。

25(○口○*)さん :06/03/25 06:59
>>4-10,13
韓国AIでも似たような仕組みが入っていますが、こっちのほうが見やすそうですね。
感謝。

で・・・この方法って、実はマウスゼスチャ的な汎用入力に拡張できるような気がしています。
で、そうすると「ケミの周囲1マスでちまちま」やるのは結構めんどくさいんですね。
以下のような感じで、画面全体を大きく割って入力できるようにすると、ちょっと便利かも。

まずは
DIRECTION_LEFT_DOWN = 1
DIRECTION_DOWN = 2
DIRECTION_RIGHT_DOWN = 3
DIRECTION_LEFT = 4
DIRECTION_CENTER = 5
DIRECTION_RIGHT = 6
DIRECTION_LEFT_UP = 7
DIRECTION_UP = 8
DIRECTION_RIGHT_UP = 9
・・・を定義する。

2625 :06/03/25 07:01
function CovertPosToID( x, y )
-- ROのクリック位置を、コマンドに変換するためのユーティリティ。
-- RO画面上、ケミからみて相対的にどのあたりをクリックしたのかを帰す関数。
-- 画面が正位置(上方向がマップの北)にあることが前提。
-- 実用上の解像度がわからんけど、経験的にこう割っておく。

-- ←計5列→
-- ID:7 | ID:8 | ID:9
-- ----------------------------------↑
-- ID:4 | ケミ | ID:6   計3行
-- ----------------------------------↓
-- ID:1 | ID:2 | ID:3
-- ケミの足元近辺はID5。

local curX,curY,retval = 0
curX,curY = GetV(V_POSITION,MyOwner)

if( x<curX-2 and y>curY+1 ) then -- 左上クリック。
retval = DIRECTION_LEFT_UP
elseif( x<curX-2 and y<curY-1 ) then -- 左下クリック。
retval = DIRECTION_LEFT_DOWN
elseif( x>curX+2 and y>curY+1 ) then -- 右上クリック。
retval = DIRECTION_RIGHT_UP
elseif( x>curX+2 and y<curY-1 ) then -- 右下クリック。
retval = DIRECTION_RIGHT_DOWN
elseif( y<curY-1 ) then -- 中央下クリック。
retval = DIRECTION_DOWN
elseif( y>curY+1 ) then -- 中央上クリック。
retval = DIRECTION_UP
elseif( x<curX-2 ) then -- 中段左クリック。
retval = DIRECTION_LEFT
elseif( x>curX+2 ) then -- 中段右クリック。
retval = DIRECTION_RIGHT
else -- 残ったのは中央。
retval = DIRECTION_CENTER
end
TraceAI (string.format("Click! (%d)",retval ))
return retval
end

2725 :06/03/25 07:05
うわ、しまった。スペーシングがずれるの忘れてた oTL
・・・まあ力ずくのコードなので、見づらくてもわかると思いますのでご容赦を。

要は「ケミの周囲1マスでのテンキー位置」ではなく、
「ケミを中心に上下3マス・左右5マスにボーダーラインを引いて、
 画面全体内でのテンキー位置」を狙っています。

28(○口○*)さん :06/03/25 09:05
余り広すぎると普通に移動させてるときにスイッチはいっちゃうから
ケミの隣接座標とかに仕込むんじゃないか

2925-27 :06/03/25 09:44
>>28
ああ、そか。これは普通のALT+右クリックだから、常時ホムが移動するのね。

すまん、俺のAIは特殊コマンド系は「学習モード」とか「ALT+SHIFT+右クリック」で
やることにしてたから、そういう状態では移動させてないのを忘れていたわ。
まあ、そういうやりかたもあるってことで、参考レベルにしておくれ。

3025 :06/03/25 13:32
何度か独自AIをあげさせてもらっている者です。
こんなこともできるよ、というアイディア提示もかねて。
#いや実は、これを作ってるときに上記4-10,13があったので、つっこんだのです。
ttp://tomose.dynalias.net/RO/attach/hom/Glenelg_023.lzh

元AIは「まずケミに攻撃している敵を攻撃」「それがいなくなったらホムへの敵」という
優先順位で索敵しますよね。でも現実を考えると本当は「よりたくさん敵がいる側を先に」とか
「より脅威度の高い敵を先に」としたいところ。
拙作AIでは、近隣の敵を一通りチェックして上記のような条件を複合的に判断して、
攻撃をできるようにしています。
operation.lua 内 GetEnemy(), CreateAttackOrder() あたりを参照のこと。

独自AIなので、元AIベースのモノへの反映は難しいかと思いますが、
なにかの参考になれば幸いです。

31(○口○*)さん :06/03/25 13:37
ぶしつけで申し訳ないんですがケミのポーションピッチャーのIDってどこかに出てました?
もしくはわかる方いればご教授いただけないでしょうか

32(○口○*)さん :06/03/25 13:42
11*21とかいってみる。

33(○口○*)さん :06/03/25 13:47
>>32
ありがとうございます。
10進数でいいんですか?

34(○口○*)さん :06/03/25 14:09
ケミスキル使用の話はやめろよマジで。

35(○口○*)さん :06/03/25 14:12
スレ汚し失礼しました。

36(○口○*)さん :06/03/25 14:59
>>13
ちょっと弄ってみた。動かしてないけどc⌒っ.д.)っ

- CommandStep[1] = { 1,3,9,7 }
+ CommandStep[1] = { 1,3,9,7,f = StepCommand_Castling }

- StepCommand_Main(i)
+ CommandStep[i].f()

- function StepCommand_Main ( i )
+ function StepCommand_Castling ()
-   if i == 1 then
      -- 手元に移動とキャッスリングを組み合わせたまったく意味の無い例
      SkillObject(MyID,5,SKILL_CASTLING,MyID)
-   end
  end

37(○口○*)さん :06/03/25 15:48
レアアイテムの周りをぐるぐる回ってくれるような「ここほれホムホム」とか
やってみたいけど未鑑定アイテム透視関係しそうだからだめぽいかなあ

ALT+右クリックで回るアイテムを学習させるとかいうタイプなら・・
と思ったけど学習したあとのファイル配られちゃったら同じだよなあ

どうする、ホムホム

   ヘヘ
  | ̄ ̄ ̄|
..∠|_( ・ω・)ゝ <みー

38(○口○*)さん :06/03/25 15:51
週末ということでGvG用AIを組むことを考えているんだが、
仕様的な問題点は

・人数が多いため、GetActors ()でローカルPCに負荷がかかる
・ラグが発生するため、同期落ちの原因になる

の2点だろうか?

前者はGetActors ()自体は通信してなさそうなので
PCの性能によっては問題にならなそう(首都が歩ければOK?)

後者については
・自動追尾、敵への粘着を使わない
・自動追尾、敵への粘着時はコマンド送信ごとにsleepを儲けるか、
 コマンド送信後一定時間同じコマンドを送信しないように設定する
・モーションでホムの行動が解決されたか監視する

といった解決手法を考えているが、どれがいいだろう。
sleepなどの場合、鯖状態によって最適sleep時間が変わると思うので
その辺は実験するしかなさそう&同志募集かなあ。

先週はGvG休んでいたので、GvGでホム連れて歩いた人は感想いただけると有難いです。

39(○口○*)さん :06/03/25 15:55
>>37
とりあえず。
現状、ホムは地面におちているアイテムを、そもそも認識できません(^^;;

40(○口○*)さん :06/03/25 16:01
>>39
Winter's Taleさんのとこの関数マニュアルGetActors()に書いてあるから出来るのかと思ってた(´・ω・`)

目が悪いホムかわいいよホム

41(○口○*)さん :06/03/25 17:33
なんかホム連れてると、マップ移動やハエ飛び直後にサバキャンされることが…
早い回線では起こらないんですが、何が原因で、どうすれば直るんでしょうか?
使用AIは0マテどきどきです。

42(○口○*)さん :06/03/25 17:52
鯖キャンというかNPCも読み込まずに無反応になることならあるな。
重くないところでも起きる。なんだろうな。
普段まともに動いてエラー吐いてないならAIのせいというかクライアントのせいの気もする。

43(○口○+) :06/03/25 19:24
中途半端にしか読んでなくて申し訳ないのですが・・・

onMOVE_CMD にAlt+右クリックした座標が渡されるのなら
その座標とケミ(あるいは対象)の座標とで StepCommand を実行して
コマンド成立したなら true 、しなかったなら false を返らせれば
わざわざ移動させなくてもだいじょぶにならないかな・・・とかとか。

-- IN CommandStep
if not isMatch then
Command_Time = 0
return false
else
return true
end

-- IN onMOVE_CMD
local ownerX,ownerY = GetV( V_POSITION,GetV( V_OWNER,MyID ) )
local IsStepCommand = StepCommand( x,y,ownerX,ownerY )
if IsStepCommand then return end

的外れなこと言ってたら申し訳ない。。。

44(○口○+) :06/03/25 19:25
おわー、タブは無視されるのね・・・
見難くて申し訳ない・・・軽く飛び降りてくる。

4513 :06/03/25 20:13
>>36
それだと StepCommand と StepCommand_Castling を同じluaファイルに書いた場合
CommandStep[1] = { 1,3,9,7,f=StepCommand_Castling() }
のときに StepCommand_Castling がまだ定義されてないってでちゃって
まぁ別のファイルに書けばいいんでしょうけどうーむ

>>43
それでいけそうですね
一応この間のページを更新しておきます
コードの発端は私じゃないけど!

あと自分で書いておいて何ですが、座標をテンキーの座標にするときに
ケミとホムの角度から出すようにすれば,真中は取れませんが
コマンド入力だと判定する範囲も簡単にきめられてコードもスマートになるかもしれない
と思いました。

(私事:引越しのためがんばっても3/30くらいまでしかネットに繋げられない('・ω・`)
 Wikiとかにおけば皆でガシガシ改良できるんだろうか…

46(○口○+)43 :06/03/25 20:21
>>45
採用どうもー。(笑
自分もコマンド入力でモード切替とか関数処理とかのAI書いてたので
良い勉強になります。^^

>>36 さんのですが、
CommandStep[1] = { 1,3,9,7,f="StepCommand_Castling" }
にすれば、
assert( loadstring( CommandStep[1].f ) )()
で呼び出せるんじゃないでしょうか。試してないケド。

47(○口○*)さん :06/03/25 21:53
>>23
有難うございます。早速使わせてもらいます〜

48(○口○*)さん :06/03/26 00:43
>>36,45,46
a = function() b() end -- この時点でbは未定義
function b() print("b") end
a() -- "b"

というわけで、
CommandStep[1] = { 1,3,9,7, f = function() StepCommand_Castling() end }

>>45
>CommandStep[1] = { 1,3,9,7,f = StepCommand_Castling }
関数そのものを代入する

>CommandStep[1] = { 1,3,9,7,f=StepCommand_Castling() }
関数の実行結果を代入する

49(○口○*)さん :06/03/26 01:40
>>45
こんな感じかな(未検証)
まずい所あったらよろしく

--------------------------------------------------------------------------------
-- id1から見たid2の方向(ラジアン角)を得る
-- 戻り値:0〜2π(右方向=0、上方向=1/2π、左方向=π、下方向=3/2π)
--------------------------------------------------------------------------------
function GetDirection( x1, y1, x2, y2 )
 local rad = math.atan2( y2 - y1, x2 - x1 )
 if( rad < 0) then
  rad = 2*math.pi + rad
 end
 return rad
end

--------------------------------------------------------------------------------
-- 座標からテンキーの位置を算出
--------------------------------------------------------------------------------
function GetKeyDirection( myid, x, y )
 local Data = { 6, 9, 9, 8, 8, 7, 7, 4, 4, 1, 1, 2, 2, 3, 3, 6 }
 local ox, oy = GetV( V_POSITION, GetV( V_OWNER, myid ) )
 -- クリック位置がオーナーの座標なら中央(5)
 if( x == ox and y == oy ) then
  return 5
 end
 -- 角度(ラジアン)からテーブルでキーを取得する (math.pi/8) = 2π/16
 return Data[math.floor( GetDirection( ox, oy, x, y )/(math.pi/8) )+1]
end

50(○口○*)さん :06/03/26 01:49
過去スレが落ちているので…
GetV(V_HOMUNTYPE, id)
で取得できるプレイヤーの職業一覧を掲載している場所があれば教えていただけないでしょうか。

51(○口○+)43 :06/03/26 02:11
>>45
なんてすっきり・・・ステキ。

うちのGetDirectionは x2-x1,y2-y1 が
同じか多いか少ないかで

52(○口○+)43 :06/03/26 02:13
うあー・・・途中で書き込み押した・・・

細かく分岐作って8方角割り振ってたましたよ・・・
頭が固い証拠ですな。(苦笑

53(○口○*)さん :06/03/26 02:17
>>50

422 名前:(○口○*)さん[sage] 投稿日:06/03/15 11:19 ID:yfmdPwF1
確かにGetActor()でアイテムID取得出来ないね・・・
GetV(V_HOMUNTYPE, id)と合わせて適当に遊んでるトコだけど
>>406以外に、ワープポイント、ギルドフラッグなんかも取得できるね
HOMUNTYPE結果はWPが45、旗が722、あとはキャラのid入れると職業取得できる
idと職業の関係は
ttp://homepage1.nifty.com/meru/
のPlayerJob.txtのIDでおk

それと多分だけど、視野範囲にいるハイド&クロクしてるMOB、PCのidを取得できるとして、
ハイド状態の敵に対して攻撃が可能ならGvの金ゴキでクロクも破れるかもしれんね

54(○口○*)さん :06/03/26 02:18
>>50


423 名前:(○口○*)さん[sage] 投稿日:06/03/15 11:24 ID:yfmdPwF1
>>418,420
プロの露天で片っ端からID取得&記録すれば分かると思うけど
取得したIDの桁数でPCかどうかは判別できると思う
18ってのはケミだね
>>422のtxtからコピペすると
0,Novice
1,Showdman
2,Magician
3,Archer
4,Acolite
5,Marchant
6,Thief
7,Knight
8,Priest
9,Wizerd
10,BlackSmith
11,Hunter
12,Assassin
14,Crusader
15,Monk
16,Sage
17,Rorg
18,Alchemist
19,Bard
20,Duncer
22,Wedding
23,Super Novice

転生職は+4001、養子職は+4023だそうだ

55(○口○*)さん :06/03/26 02:29
ありがとうございます。

とりあえずPvPで画面内の詠唱中キャラにカプリスを打ち込むことができました。
が、詠唱ならなんでも反応してしまうのでこれから職区別をつけてみます。

56(○口○*)さん :06/03/26 07:09
Move(id,x,y)で指定した移動先が、進入不可セルかどうか認識させることってできます?

57(○口○*)さん :06/03/26 08:45
>>56
難しそう、というのが今の見解です。

・Move()には直接的な戻り値がないので、戻りを用いて判定することは不可能。
・OnMoveCMD_STで座標監視すれば、ホムが一定時間移動しないことはわかりますが、それは
 「そのセルが進入不能」なのか、
 「壁向こうを指定している(そのセル自体は入れるが、経路が進入不能)」なのかが
 わかりません。

自分の隣りセルをMove対象にして時間監視、という手を使えば、多少は可能性はあるかも。
でも重力座標で移動しないケースもありますので、過信は禁物。

58(○口○*)さん :06/03/26 08:51
要望雑談スレ355対応。
トレースレベル指定
-- gloval で表示するレベル指定。
TRACE_LEVEL = 0

function Trace( text, level )
 if( level ~= nil ) then
  -- レベル記載省略時。通常トレース
  TraceAI( text )
 elseif (level >TRACE_LEVEL) then
  -- レベル記載時。条件付でトレース。
  TraceAI( text )
 end
end

上記がある前提なら、
Trace( "output" ) -- 従来のTraceAI()と同等動作
Trace( "output", 2) -- TRACE_LEVEL >2 のときだけ表示。

59(○口○*)さん :06/03/26 08:56
>>57
なるほど。レス有難う。

60(○口○*)さん :06/03/26 09:25
>>58
TraceっていうFunctionがクラ側で定義されてる。
なにかはよくわからないけどあった。

61(○口○*)さん :06/03/26 10:49
>>58
if( level ~= nil ) then
諸略なら level == nil じゃないかな?

62(○口○*)さん :06/03/26 11:07
>>48
それで無事動きましたーGJです。勉強になります

>>49
まずい所なかったです
合えて言うなら私がStepCommand内で呼び出すときに
local stepNumber = GetKeyDeirection(myid,x,y)
ってそのまま書いちゃって因数がnilってエラーでちょっと悩んだくらいorz

--あとはあの野暮ったい行列をとっぱらいところですが、
そろそろ(引越し準備の)時間的余裕が
無くなってきましたのでオラの出番がここまでだちくしょう
まぁ商人系は常に西を把握してるから回転体(?)にこだわらなくてもいいんだけどね

6313=15=45=62 :06/03/26 11:09
名前欄書き忘れました↑ですノシ

64(○口○*)さん :06/03/26 13:23
>41
自分で作ってるから0マテは知らんが、Moveを乱打してるようなAIだと
経験上かなりの確率で落ちるよ

6558 :06/03/26 15:00
>>61
Σ('-'つ)つ
ほんとだ、論理逆だ・・・失礼しました。指摘さんくす。

#外出前5分で書いた、というのは言い訳にならないよね(^^;;

661/2 :06/03/26 15:31
----------------------------------------
-- 主人寝落ち対策 - NeochiCheck(myid,msg,rmsg)
-- AI() 内で NeochiCheck(msg,rmsg) のように入れておく。
-- msg,rmsg にはGetMsg,GetResMsgの値を入れる。myid 以外は省略可能。
-- 無反応時間が NEOCHI_LIMIT の1/4になったらホムが四方を回りはじめる。
-- 無反応時間が NEOCHI_LIMIT に達するとクライアントを終了する。
----------------------------------------
NEOCHI_LIMIT = 60000 * 40   -- 無反応で強制終了する時間(単位ミリ秒)
function NeochiCheck(myid,msg,rmsg)
    local tick = GetTick()  -- 現在時間
    local owner = GetV(V_OWNER,myid)    -- 主人ID

    if (Neochi == nil) then     -- 初期化
        TraceAI("NeochiCheck: INITIALIZE_IN")
        Neochi = {X=-1,Y=-1,Motion=-1,Way=-1,Limit=tick+NEOCHI_LIMIT,CoaxLimit=tick+NEOCHI_LIMIT/4,CoaxDelay=-1}
        return
    end

    if (msg ~= nil and msg[1] ~= NONE_CMD) then -- コマンドを送った
        TraceAI("NeochiCheck: SEND_MESSAGE_IN")

        Neochi.Limit = tick + NEOCHI_LIMIT
        Neochi.CoaxLimit = tick + NEOCHI_LIMIT / 4
        return
    end

    if (rmsg ~= nil and rmsg[1] ~= NONE_CMD) then   -- 予約コマンドを送った
        TraceAI("NeochiCheck: SEND_RES_MESSAGE_IN")

        Neochi.Limit = tick + NEOCHI_LIMIT
        Neochi.CoaxLimit = tick + NEOCHI_LIMIT / 4
        return
    end

    local x,y = GetV(V_POSITION,owner)
    if (x ~= Neochi.X or y ~= Neochi.Y) then    -- 違う座標へ移動した
        TraceAI("NeochiCheck: MOVE_IN")
        Neochi.X,Neochi.Y = x,y -- 新たな座標を記憶

672/2 :06/03/26 15:31

        Neochi.Limit = tick + NEOCHI_LIMIT
        Neochi.CoaxLimit = tick + NEOCHI_LIMIT / 4
        return
    end

    local motion = GetV(V_MOTION,owner)
    if (motion == MOITON_MOVE or motion ~= Neochi.Motion) then  -- 違うモーションを起こした
        TraceAI("NeochiCheck: ACTION_IN")
        Neochi.Motion = motion  -- 新たなモーションを記憶

        Neochi.Limit = tick + NEOCHI_LIMIT
        Neochi.CoaxLimit = tick + NEOCHI_LIMIT / 4
        return
    end

    if (tick > Neochi.Limit) then   -- 一定時間無反応だった
        TraceAI("NeochiCheck: FORCE_EXIT_IN")
        os.exit()   -- 強制終了

    -- 残り時間間近になったら回ってねだる
    elseif (tick > Neochi.CoaxLimit and tick > Neochi.CoaxDelay) then
        TraceAI("NeochiCheck: COAX_IN")
        local x,y = GetV(V_POSITION,owner)
        Neochi.CoaxDelay = tick + 500
        if (Neochi.Way == 0) then
            Move(myid,x+1,y)
            Neochi.Way = 1
        elseif (Neochi.Way == 1) then
            Move(myid,x,y-1)
            Neochi.Way = 2
        elseif (Neochi.Way == 2) then
            Neochi.Way = 3
            Move(myid,x-1,y)
        else
            Neochi.Way = 0
            Move(myid,x,y+1)
        end
    end
end

68(○口○*)さん :06/03/26 15:34
>>65
コードの確認も含めてAIスレかと。

自力で防ぐべきだけど最悪の事態を避けるために一応寝落ち対策を組んでみた。
自分は寝落ちじゃなくても忘れてることは多いんでアクションで分かるようにしてみた。

69(○口○*)さん :06/03/26 15:34
訂正、
-- AI() 内で NeochiCheck(msg,rmsg) のように入れておく。
じゃなくて
-- AI() 内で NeochiCheck(myid,msg,rmsg) のように入れておく。

70(○口○*)さん :06/03/26 15:44
すっごい久々に覗いたら浦島気分。
Mobデータベースとかできてるけど、
MobのIDてランダムで特定できないて話じゃなかったっけ?
過去ログ読みたかったんだけど、Dat落ちしてて。
気になるんで、だれか教えてくださいなー

71(○口○*)さん :06/03/26 15:46
やあドク。
GetV(V_HOMUNTYPE,id)
の値がホムの種類だけじゃなくてmobの種類もあることがわかったんだよ。

72(○口○*)さん :06/03/26 15:57
> 71
なるほどー。時代は進化してるんだねー。
教えてくれてありがとー

73(○口○*)さん :06/03/26 16:15
ALT+Tをトリガーにして行動を替える部分の書き方が分りません

74(○口○*)さん :06/03/26 16:19
コード関係は流し読みしてる部分が多いので、すでに解決してるかも
しれないんだが、ちょっと改良方法のアドバイスが欲しい。

まず、自分が調べたことなんだが、
・モンスターを倒した直後に、
「別ID、IsMonsterの返り値1、ターゲット同じ、モーションいろいろ、同座標」
な状態になっているもよう。(多分、死亡状態を別IDで管理してるんだと思う)

で、改良したい点としては、
・モンスターを倒したあと、死亡状態になっているモンスターを攻撃しに行ってしまい、
それが消えるまで攻撃しない状態になってしまう。

いまは、死亡状態のなり始めがMOTION_DEADであることが多いので、
それを攻撃対象から省くことである程度は大丈夫なんだが、やっぱり完全に省きたいと思って
なにかいい解決法はないかなと。


モンスターのIDを調べていたら、通常のモンスターが5万台、
死亡状態の方は4万台だったんだが、調査数が少ないし、
これを信用してコードを組んでいいものか悩んでる。
通常モンスターのIDの一部が4万台も使ってるようだと困るし。

75(○口○*)さん :06/03/26 16:30
>>74
前に書いたけどIDが-1になってない?
unsigned だと494065645841247くらいのでかい値じゃなかったかな。siguned だと -1 になるはず。
断定はできないけど死亡消滅時とかワープインアウトとかのオブジェクトがこれっぽい。
全然違う値だったら関係ない話。

76(○口○*)さん :06/03/26 16:35
4294967295だった。

7774 :06/03/26 16:55
>>75
-1とは違う値でも起こってる。(-1でも起こるかどうかは分からない)

細かく書いておくと、ターゲット選択のとき、
( IsMonster(ID)==1 and not IsOutOfSight(MyOwner,ID) )
がtrueのときにターゲットになりうるとして判定してる。
調べてないんだけど、ID=-1だとIsMonsterではじかれる気がする。

調べた方法を書くと、

>ホムの設定
・主人を攻撃しているモンスターに隣接後攻撃
・攻撃対象のモンスターのID、座標、モーションをTraceAIで記録
・攻撃対象を選んだ基準をTraceAIで記録
(主人のTargetである、Targetが主人である、Targetがホムであるのどれか)

実験内容
1、安息
2、ロッカのタゲを取り、ロッカが2,3回攻撃するまで少し待つ
3、コールホム
4、ホムがロッカを倒すまで待つ
5、倒したらしばらく待ってから安息

TraceAIの結果
・ほぼ確実に、攻撃対象のモンスターのIDが2回記録される
・1回目は5万台、2回目は4万台(ただし、試行回数が少ない)
・どちらのIDの場合も「Targetが主人」であった
・ロッカの場合、2回目のモーションはMOTION_DEADだった。
(他のモンスターの場合、MOTION_STANDなども見られた)

78(○口○*)さん :06/03/26 19:20
1時間ほどプロのIDとHOMUNTYPE拾ってみたんだけど
4万台はホムにもよく出てるんで識別には使えないかな。
ホムは2〜4万台、プレイヤーは10万台以降だった。あと5万に通常NPCのIDも見て取れるな。
多分PCとNPCの区別はつけられるけどそれ以外は難しいかもしれない。
死に消滅中に常にMOTION_DEADが出てくれりゃ問題ないんだがなー

79(○口○*)さん :06/03/26 20:19
>>66-67 おかしなとこあったんで直して固めてあげました。
ttp://www.mmobbs.com/uploader/files/114.zip

8074 :06/03/26 21:55
>>78
情報ありがとう。

自分としては、IsMonsterで1が返るIDのうち、
5万台>通常モンスター、4万台>死に消滅中
なら、>>74の問題は解決できるんじゃないかと思ってる。
(ホムが4万台でも、IsMonsterで1が返らないので、なんとかなる)

自分が使ってるAIに調べるのに不具合があるバグがあるので
それが解決したら、4万台、5万台のIDで区別を入れてみて、実際に
どうなるかやってみようと思う。

#1秒殴らない程度だからほっといてもいいんだけどね。

81(○口○*)さん :06/03/26 23:13
>>58
サンクスコ。要望出したモンだけど、お礼代わりに自分なりにカスタマイズしたのを張っとく。

レベル指定なし、は無条件出力じゃなくて、最低レベルとして扱うことにした。
もともとあるTraceAI文に全部優先度を設定するのが面倒だから、
TraceAI→TraceAI2 の文字列置換のみで済ませたかったんよ

実際使ってみたらTRACE内容がすっきりして大満足でした。


TRACE_LEVEL   = 2  -- TraceAIで出力するレベルの指定
TRACE_MODE    = 1  -- 0:すべて出力 1:指定レベル以上を出力 2:指定レベルのみ出力


-------------------------------------------
-- レベル指定トレース
-------------------------------------------
function TraceAI2( text, level )
  if( level == nil ) then
    level = 0               --- level指定がなければ最低levelに置き換え
  end

  if (TRACE_MODE == 0) then     --- モード0:levelに関係なく出力
    TraceAI( text )
  elseif (TRACE_MODE == 1) then  --- モード1:指定レベル以上の情報出力
    if (level > TRACE_LEVEL) then
       TraceAI( text )
    end
  elseif (TRACE_MODE == 2) then  --- モード2:指定レベルのみ情報出力
    if (level == TRACE_LEVEL) then
       TraceAI( text )
    end
  end
end

82(○口○*)さん :06/03/26 23:17
あっ、以上とかいいつつ以上になってない。

-    if (level > TRACE_LEVEL) then
+    if (level >= TRACE_LEVEL) then

83(○口○*)さん :06/03/26 23:21
>>38
GetActors使ってるとこ省いたAIでGv参戦してみました。
環境はそこそこ性能のいいPCです。
結果は×、ラグラグですね。

蔵鯖間の通信を抑制しないといけないってことですか。

84(*○口○)さん :06/03/26 23:34
>>80
死んだ敵に対する対処なら既に過去ログに出ている
OnATTACK_ST、OnCHASE_STで敵がMOTION_DEADか画面外なら待機、
GetOwnerEnemy、GetMyEnemyでMOTION_DEADの敵を対象としない
是で十分じゃないか?むしろこれ以上スマートな方法が現状無いと思うが・・・

1匹殺して次の敵に移るのが遅いのは何も死んだ敵に執着しているからだけじゃないぞ?
OnATTACK_STをスタートに見れば
攻撃状態(MOTION_DEAD確認)-- AI(myid) 0回目

待機状態(ケミの敵をセット)-- AI(myid) 1回目

追跡状態(既に射程内とする)-- AI(myid) 2回目

攻撃状態(ココで始めて攻撃)-- AI(myid) 3回目

この流れその物が「遅い」原因だろ?
MOTION_DEADの確認をしたらまず、周りに敵が居ないかサーチして居たら
即MyEnemyにセットして攻撃状態を維持してしまえばいいじゃないか

攻撃状態(現在の敵のMOTION_DEAD確認)-- AI(myid) 0回目
ケミorホムの敵を探す→いない(通常通り待機状態へ)
↓居る
該当の敵をセット(ココまでをOnATTACK_STで処理)

待機状態or攻撃状態(新しい敵)-- AI(myid) 1回目

っとケミが課金切れなのでネタだけ放ってみる

85(*○口○)さん :06/03/26 23:43
追記
実際のプレイヤーがやる判断を状態遷移に組み込むだけだが、
基本の遷移状態を蔑ろにしやすいのでスパゲッティにならないように注意

86(○口○*)さん :06/03/26 23:49
使いやすいAIってどれー?

87(○口○*)さん :06/03/26 23:52
>>86
わかんないなら片っ端から試して糞して寝ろ

88(○口○*)さん :06/03/26 23:54
何だとこのやろう

89(○口○*)さん :06/03/27 00:15
>>84,85
IDLE→CHASE→ATTACKという状態遷移の都合上、実際に攻撃するまでにAI()が3回呼ばれるから、
鈍いよ、ということですよね。
これ、別にIDLEの中で追加判定・CHASEの中で追加判定・・・としなくても、結構早くする方法があります。

AI() の中、
if (MyState == IDLE_ST) then
OnIDLE_ST ()
elseif (MyState == CHASE_ST) then
OnCHASE_ST ()
elseif (MyState == ATTACK_ST) then
OnATTACK_ST ()
(以下略)
・・・と、「if〜elseif〜・・・」と連鎖的にチェックしていますよね。
ここの「else接続を止める」だけで、いきなりAI() 1回でIDLEからATTACKまでたどりつきます。

if (MyState == IDLE_ST) then
OnIDLE_ST ()
end
if (MyState == CHASE_ST) then
OnCHASE_ST ()
end
if (MyState == ATTACK_ST) then
OnATTACK_ST ()
(以下略)

90(○口○*)さん :06/03/27 00:16
>>86
ぜろまて


人によりけりだから自分で試すしかないんだよ。

9174 :06/03/27 00:22
>>84
体感で申し訳ないんだが、最も早く攻撃に移る場合は、
ほとんど倒した直後に(死亡イフェクトが残ってる状態で)次の敵に向かって移動開始をしてる。

なので、状態遷移の多さが遅い原因ではないと考えている。
(状態遷移の多さが原因だったら、毎回遅いはず)

>1匹殺して次の敵に移るのが遅いのは何も死んだ敵に執着しているからだけじゃないぞ?

他の原因も考えられないわけじゃないんだが、
>>77の実験とかAIを使った感じからすると、「死んだモンスターに執着している」
と考えるのが一番妥当だと思ってる。

92(*○口○)さん :06/03/27 00:51
>>91
確かに状態遷移が多くても状態遷移その物が速ければ何の問題も無いんだ
実際、自分も遷移の遅さなんて体感した事は無い(PCの性能に左右されるかも・・・
敵の死にモーション対策が出来ているのに遅いなら・・・の意味で放ってみたんだ

で、よく読み返してみれば敵の死にモーション対策がまだなのかな?
GetOwnerEnemyとGetMyEnemyの、GetActors()から敵のリストに追加する手前で
if (GetV(V_MOTION,v) ~= MOTION_DEAD) then -- 敵が死にモーションでなければ
これで死にモーション中の敵を除外

OnATTACK_STとOnCHASE_STの冒頭部分で
if (true == IsOutOfSight(MyID,MyEnemy)) then -- ENEMY_OUTSIGHT_IN
の代わりに
local EnMo = GetV(V_MOTION,MyEnemy) -- 敵のモーションを取得
if (EnMo == -1 or EnMo == MOTION_DEAD) then -- 敵のモーションが取得出来ないか敵が死にモーションならば
これで画面外に出るとモーションが取得できないことを合わせてチェック

この2つで自分はボルセリオで試したけどすぐ他の敵に殴り始める様になった

93(*○口○)さん :06/03/27 00:57
ボ(BO)じゃ無くてポ(PO)か・・・

>>89
毎回全てのステータス状態についてチェックするってのが
無駄っぽくて余り好かんのでね。スマン

94(○口○*)さん :06/03/27 01:57
>>93
ああ、全部やる必要ないですよ。
わたしはIDLE、CHACE,ATTACK だけそうしてます。
確かに全部やるってのは、わざわざ状態わけしている意味が弱まるので、
そこまでやるのは好ましくないと思います。

このやり方の場合、状態の論理的意味合い・状態動作実体は変わっていないので、
論理的な齟齬がうまれようがないのがメリット。
状態の意味合い的にも、これらの3状態は他のモノに比べてちょっと違うので、
私的にも妥協の産物です。
#充分な処理性能が確保できるのなら、こんなことをしなくていいわけですから。

まあいずれにせよ、91==74氏のコメントから、これは本筋ではなさそうですけどね(^^;;

95(○口○*)さん :06/03/27 02:03
>>81を string.format の書式に対応してみた。

TRACE_ALWAYS = 0  -- 常に出力
TRACE_ABOVE = 1   -- 指定レベルより上を出力
TRACE_EXCLUSIVE = 2   -- 指定レベルのみ出力

TRACE_LEVEL = 0  -- TraceAIで出力するレベルの指定
TRACE_MODE = TRACE_ABOVE  -- モードを設定

TRACE_DEFAULT_LEVEL = 0  -- 引数省略時のレベル

function trace( level, format, ... )  -- levelは省略可能 format以降は string.format と同じ
  local text
  if type( level ) == "string" then  -- level 省略時
    text = string.format( level, format, unpack( arg ) )
    level = TRACE_DEFAULT_LEVEL
  else
    text = string.format( format, unpack( arg ) )
  end
  if TRACE_MODE == TRACE_ALWAYS then
    TraceAI( text )
  elseif TRACE_MODE == TRACE_ABOVE and level > TRACE_LEVEL then
    TraceAI( text )
  elseif TRACE_MODE == TRACE_EXCLUSIVE and level == TRACE_LEVEL then
    TraceAI( text )
  end
end

96(○口○*)さん :06/03/27 02:04
local x, y = 12, 14
trace("debug print")
trace("move: %d,%d", x, y ) -- move: 12, 14
trace( 2, "move: %d,%d", x, y )   -- レベル指定

書式だけなら
TraceAI( string.format("move: %d,%d", x, y ) )
でもトレースできるけど、
/traceai がOFFになってても文字列置換を行うので
上のほうが高速

あとここにTraceAIをカスタマイズする方法も載ってるんで
読んでみるといいかも
ttp://blog.livedoor.jp/aidev/archives/50202417.html

97(○口○*)さん :06/03/27 02:15
ああすまん、
>>96の高速うんぬんは嘘だわw
/traceaiがOFFの時はstring.formatの置換処理はやめたかったんだけど、
AI側から知る手段がないしね。TraceAI.txtのサイズなんか調べてたらよけいに遅くなるし
まぁ、LuaがLight-weightな言語だから
些細な負荷は無視すりゃいいって言えばそうなんだけど

98(○口○*)さん :06/03/27 02:21
遅レスで申し訳ありません。
前スレ950で質問した者です。
皆さんのヒントや他の人のAIを見たりしてようやく思ったように動くようになりました。
追加で逃亡用コマンドを作って、それを攻撃中やつ伊籍中の所に呼び出せ(?)ばよかったのですね。
答えて下さった皆様、ありがとうございます。

最初OnIDLE_ST内の最後に書いたのは逃亡AIにTraceAI ("IDLE_ST -> FOLLOW_ST")という文があったので
OnIDLE_ST内のそれがある部分を書き換えればいけるのかなと思ったからで、
DistanceNotReturn=0なのは、なんかエラー出る→DistanceNotReturnが怪しい→とりあえずDistanceNotReturn=0ってしてみよう
→エラー出なくなったからこれでいいのか という訳です。
ハズカシー

99(○口○*)さん :06/03/27 02:36
>>92
いや、そういう話ではなくて、>>77 によると
「死にモーション中なのに MOTION_DEAD を返さない輩がいるように見える」そうです。
>>77 氏のいう「他のモンスター」というのは、具体的には何でしょう?
・・・と人任せもアレなので、できたら私も調べてみます

10099 :06/03/27 04:42
調べるなどと書いたけど、よく考えたら私は iRO の住人なので
もしかすると jRO とは仕様が違うかもしれません。あくまで参考程度に。

クッキー(赤、緑いずれも) に対してホムで攻撃して倒すと、
直ちに別 ID の死体オブジェクトに入れ替わる。
時々、死体オブジェクトが MOTION_STAND を持っていることがあるが
すぐに MOTION_DEAD に変化する。
想像だけど、死体オブジェクトは MOTION_STAND で現れて
直後に MOTION_DEAD に変化するため、
AI() 実行のタイミングによっては MOTION_STAND を拾ってしまうのではなかろうか。

「今まで攻撃していた相手と同じ位置に同じ種類の敵が MOTION_STAND
でいる場合、それは死体とみなす」という方法で回避できるんじゃないかな?

101(○口○*)さん :06/03/27 04:56
>>100
同じ座標に複数体重なっている時に問題になりそうな気がしないでもないがどうなんだろう

この問題に関連しているっぽいので敵を倒したあと、画面内に即沸きするとIDが同じなので
攻撃に行ってしまうという問題がある。
MyEnemyのターゲットも保存しておいてそれが変わったら(0なら)別の敵と認識しないとダメかもしれない
確認しようと思ったけどそうそう即沸きする場面に出くわさないし眠いので寝ます |∀・)ノシ

102(○口○*)さん :06/03/27 08:59
>>100
あるある。
MOTION_DEAD/-1取ったらMyEnemy=0とかにしても殴りに行くんだよな。
環境依存では無いんだろうから鯖側…か。
MOB座標取っておいて急に何セルか飛んだらMyEnemyリセットするぐらい?

103(○口○*)さん :06/03/27 10:24
死んだモンスは x,y座標で -1 返すようになった気がする。
同画面内に同じIDで出た場合は知らないけど、死亡判定ならこれぐらいでもいい気がする。

関係ないけど、ホムの攻撃・詠唱モーションって取れなくない?
攻撃成功したか、スキルを使用できたか、の良い判定方法ないかな・・・。

104(○口○*)さん :06/03/27 10:38
>>103
死亡確認はそういう方法でいけますが
同座標に死体オブジェクトが、生前と同じターゲットを保持したまま残るようです。
すぐに MOTION_DEAD になるので、モーションを監視していれば判別できますが
死亡直後は一時的に (0.2 秒ぐらい?) MOTION_STAND になっているようなので
ほんの少しですが、無駄な動きをしてしまいます。
>>80氏の提案が使えるなら、この無駄は省けそうだけど・・・

前回 AI() 実行時のホム SP を覚えておいて、
現在のホム SP が減っていれば「前回 AI() 実行時にスキル使用した」
という判断はできます。

105(○口○*)さん :06/03/27 11:12
>>104
死亡確認が取れているのに、モーション見る必要はないような?
-1ではない正常な座標が返ってきちゃうのかな?

SPチェックがあったか。
ちょっと練ってきます。

106(○口○+) :06/03/27 12:43
SPチェックでスキル使用したか否かの判断は
前スレでちょっと話したりしました。前スレ 783,824,849,851 参照。

で、結局出来なかったのであとは頼みます・・・

107(○口○*)さん :06/03/27 14:51
少しまごついてる位のほうが、ホムはかわいいとか思ってしまう俺は
狩り用AIではなく、愛でる用のAI開発に力を注ぐべきかなw

108(○口○*)さん :06/03/27 15:12
ちょっと質問だけど
キャスリングで偽残影とか
似非バクステとかできる?

109(○口○*)さん :06/03/27 15:27
>>108
何がやりたいんだ?AIスレ向けの話題じゃないな
地点指定→ホム移動→移動完了でキャスリング ってのは自動化出来なくは無い

けど、そういう事を言いたい訳じゃないんでしょ?

110(○口○*)さん :06/03/27 17:34
くまーAI使ってみてるんだけど、デフォの時みたいにケミでタゲとってもホムが攻撃してくれない(´・ω・`)
どこいじれば共闘してくれるようになるんですか?

111(○口○*)さん :06/03/27 17:55
>>106
スマートじゃないけど、こういうのじゃダメ?
まだデバッグしてないからなんとなく手順だけ。

MyLastSP = 0 -- スキル発動直前のSP量
SkillTimer = 0 -- スキル発動時間
SkillInterval = 0 -- スキルディレイ
SkillMotion = 0 -- スキル発動フラグ

function SkillUse(user,lv,id,target,sp,inteval)
    local mySP = GetV(V_SP,MyID)
    if (mySP > sp) then -- 消費SPより多ければ
        if (GetTick() > SkillTimer + SkillInterval) then -- スキルディレイが終わっていれば
            SkillObject(user,lv,id,target) -- スキルのセット
            MyLastSP = mySP
            SkillTimer = GetTick()
            SkillInterval = inteval
            SkillMotion = 0
        else -- スキルディレイ内で
            if (SkillMotion == 0 and mySP >= MyLastSP) then -- SPが減っていなければ、発動していないと見なし
                SkillObject(user,lv,id,target) -- スキルのセット
                MyLastSP = mySP
                SkillTimer = GetTick()
                SkillInterval = inteval
            else
                SkillMotion = 1 -- 発動してるっぽいのでチェック
            end
        end
    end
end

112(○口○*)さん :06/03/27 17:57
>>110
くまーAIは知らないが、
普通はホムの攻撃対象の候補を取得する部分をいじり
ケミをタゲっているモンスターも攻撃対象として含むようにすれば
攻撃してくれるようになるのではないかねお嬢さん

113(○口○*)さん :06/03/27 19:42
死亡判定に苦しんでるようですね。

自分はAtack(id,v)の直後にもモーション判定を入れることで
以前より若干マシなった気がします。
ちょっと試してみそ。

114(○口○*)さん :06/03/27 19:48
>>110
おれもくまAI使ってるけど、
ケミでタゲとればちゃんと攻撃してくれるぞ?

待機状態だったりしない?
デフォルトのままつかってると、始め待機状態だから
ALT+Tで攻撃する状態にしないとだめ。

それを直すなら、↓をいじれば良い。

くまAIの説明より抜粋。

> FlagDefaultState = YES 2006/03/21 01:45
>
> 有効にすると、ホムが出現した時(MAP移動,キャラセレ,安息⇒コール)に
> 非索敵状態(敵を攻撃しない状態)になります。
>
> MAP移動したら勝手に土星さんを殴って
> 死んでいたなんてことがなくなります。(ノ(ェ)`)
> (非先攻型にしとけよ、という突っ込みは無しで。)

115(○口○*)さん :06/03/27 20:36
ホムのタゲの優先順位を設定したいんだけどいい方法ないかな?
ケミの攻撃対象>ホムの攻撃対象>ホムの被ダメ先>ケミの被ダメ先
みたいな優先順位にしたい

116(○口○*)さん :06/03/27 20:54
その順番に判定して、該当したらタゲをリターンして抜ければいいだけかと。

117(○口○*)さん :06/03/27 20:57
>>115
ケミの攻撃対象は GetV(V_TARGET,GetV(V_OWNER,MyID)) で取れるからこれが0以外のときにその敵にすればいい。
ホムの攻撃対象?ホムの攻撃対象は一度決めたら固定だから判定するのは対象がいないときで意味ないんじゃない。
実質、一行目の主人の攻撃対象を GetMyOwner の頭にでもいれれば済むんじゃないかな。
自分はそうしてるけど。
    -- 主人が攻撃中の目標を最優先で狙う
    local target = GetV(V_TARGET,MyOwner)
    local type = GetV(V_HOMUNTYPE,target)
    if (target ~= 0 and IsMonster(target) and IsOutOfSight(GetV(V_OWNER,MyID)) == false) then
        return target
    end

118(○口○*)さん :06/03/27 21:06
>>115
工体AIさんところので、順番が入れ替えられるようになってるみたいです
・・・だけど、ケミが攻撃している対象がどこに入ってるかはわからないです。

拙作AIでも似たようなことはできるようにしていますが、独自AIなので
ちょっと汎用的ではないです・・・一応紹介しておきます。
ttp://tomose.dynalias.net/RO/attach/hom/Glenelg_023.lzh

operation.lua 内、 GetEnemy(),CreateAttackOrder()あたりを参照のこと。
何かの参考になれば。

119(○口○*)さん :06/03/27 21:08
>>110
個別のAIに関する質問は配布ページかAI雑談スレで
聞いた方がいいんじゃないか?

>>114
コピペまずくね?

と、自治房のおれが言って見る

120(○口○*)さん :06/03/27 21:17
@普段は自動フリットムーブOFF
       ↓
A手動でフリットムーブLv1使用
       ↓
B再使用スイッチON。
 効果が切れたら自動でフリットムーブLv1再使用
       ↓
C再使用スイッチON中に手動でフリットムーブLv1
       ↓
D再使用スイッチをOFFにする

これを実装しようといろいろ試してみたところ
Aの部分の手動でスキルを使ったという情報が取得できませんでした。
これは仕様上無理なんでしょうか?

121(○口○*)さん :06/03/27 21:22
>>120
OnSKILL_OBJECT_CMD が呼ばれるはずだから
引数の skill .と level を見ればON/OFFはできるはず。

122115 :06/03/27 21:50
俺のAIが変だから問題あるんだな・・・
よくわからんからあきらめるよorz

123(○口○*)さん :06/03/27 22:04
>>121
そう思って各所にトレースかけて動かしてみたんですが
何回やってもログ真っ白なのです。
で、AIと関係無い場所で処理されてるんじゃないかなと思った次第。

124(○口○*)さん :06/03/27 22:06
既出。対象指定スキルしか拾えない。

125(○口○*)さん :06/03/27 22:09
>>123
ログ真っ白ってのはデフォルト準拠のAIならありえない。
/traceai すれば待機状態でも OnIDLE_ST が呼ばれ続けるはず。
どこのAI使ってるのかな。

126(○口○*)さん :06/03/27 22:09
あ、フリットムーブか。
ムーンライトと勘違いしてたごめん。 >>124 です。

127(○口○*)さん :06/03/27 22:35
ちょっと1つ要望というかお願いがあります
このスレでAIあげてくれている人は
なるたけトリップかHNつけていただけるとうれしいです
うpろだのどれが誰やら・・・・>w<

128(○口○*)さん :06/03/27 22:46
>>124
既出でしたか。
これができれば応用してオーバードLv1〜5それぞれに
適当なスイッチ割り当てられて便利だなーと目論んでたんですが
どうやっても無理なようですね。ありがとうございました。

>>125
デフォルトのAIにいろいろ機能追加した自分仕様のやつ使ってます。
ぶっちゃけると16で晒したやつです。
/traceai → フリット使用 → /traceaiで
必要なタイミングだけ出力させました。

129(○口○*)さん :06/03/28 02:09
何だか止まったな。話題出尽くしたかな

1301/2 :06/03/28 02:50
んじゃ今使ってるこんなネタを投下。
OnAttack_ST()内の攻撃動作の直前(デフォAIならif (MySkill == 0) thenの上)に記述。
重力座標などに嵌ったときはmobを適当に動かしてください。
拙い知識で書いてますので一部おかしいところとかあるかもしれません。

 -- 攻撃中他キャラと重なってたらランダムでセルを移動
 if GetV( V_MOTION, MyID ) == MOTION_MOVE then -- 座標に達してなければ
  return
 end
 local MoveX = 0
 local MoveY = 0
 local actors = GetActors()
 local other = 0
 for i,v in ipairs(actors) do
  if (v ~= MyID) then
   PosX, PosY = GetV (V_POSITION,v)
   MyPosX, MyPosY = GetV (V_POSITION,MyID)
   if(PosX == MyPosX and PosY == MyPosY) then
    other = 1
    break
   else
    other = 0
   end
  end
 end

1312/2 :06/03/28 02:51
 if(other > 0) then
 MyDestX, MyDestY = GetV (V_POSITION,MyEnemy)
  MyPosX, MyPosY = GetV (V_POSITION,MyID)
  local DiceX = math.floor(math.random(3))
  local DiceY = math.floor(math.random(3))
  MoveX = MyDestX + DiceX - 1
  MoveY = MyDestY + DiceY - 1
  local move = 0
  actors = GetActors()
  for i,v in ipairs(actors) do
   local actorx, actory = GetV (V_POSITION,v)
   if (MoveX == actorx and MoveY == actory) then
    move = 1
    break
   end
  end
  if (move == 0) then
   Move(MyID,MoveX,MoveY)
  end
  return
 end

132(○口○*)さん :06/03/28 02:59
ゴキMAPでわらわら寄ってくるゴキの上でどう動くか考えるとちょっと
ほくそえましい

133(○口○*)さん :06/03/28 08:17
餌か本当に覚え間違いか判らないが…

ほくそ笑ましい

は、おかしい。
今のウチに直しとけやー

134(○口○*)さん :06/03/28 08:25
>>130-132
ゴキを踏んでしまって、避けようとしたら、また踏んで、
あわわ、あわわと、うろたえるリーフたんを想像した(´∀`)

135(○口○*)さん :06/03/28 08:40
全力モード搭載してくれた106.zip氏。かなり有用に使わせて頂いてますー。
そしてちょっとバグ?報告を。
スキル(インベとか)で攻撃してもホムが相手をタゲってくれないみたいです。
その後相手に殴られるか、こっちが通常攻撃を当てるとホムも攻撃を開始してくれるんですが…。
なんだろう。バグかな。

あと可能ならもうひとつ要望があります。
フリットが切れたら勝手にかけなおすとかできますか?

136(○口○*)さん :06/03/28 10:11
>>133
最近は妙な日本語が流行ってるのか?怒りが有頂天とか。

137(○口○*)さん :06/03/28 10:29
ほくそ笑むと微笑ましいでほくそえましいだろ?
何も問題無いじゃないか・・・

138(○口○*)さん :06/03/28 10:49
少なくとも、国語辞典に載っているような単語じゃないな>ほくそ笑ましい
微笑む・微笑ましいとの類似性から見て
「見ているとなんとなくほくそ笑んでしまうような様子」
・・・という造語としてはアリかもしれないが、まあそれなら「微笑ましい」で十分かと。

#「微笑ましい」は「微笑む」の活用ではないのよ。

以上、すれ違い失礼。

139(○口○*)さん :06/03/28 10:58
>>136
今106AI見てみたけど、もともと「ケミが殴った相手を一緒に攻撃」する仕組みは入っていない様子。
ケミが殴った相手をホムが攻撃していたとすれば、それは
「敵がケミを攻撃したので、それに対して反撃」
している動作のはず。
インベナムでタゲをとっても、その相手がケミに反撃してくれば同じようにホムも反撃しそうですけど
・・・何か手をいれてます?

140(○口○*)さん :06/03/28 12:55
とりあえずいろんなAIへの組み込み用に
各限定条件上での敵リストを返す関数群でも作って纏めといたほうがいいかね

○○な敵の中から○○を優先したいみたいな質問もあちこちで絶えないし

直接組んでIDひとつ返してくるより
先にリストそのものを条件で絞って返して
そのリストに対して自分に近いだとかケミに近いだとか
好みの選択をさせたほうがどのAIでも使いまわせていいとおもう

特定IDをタゲっている敵のリスト
 ケミをタゲっている敵のリスト
 ホムをタゲっている敵のリスト
交戦中の敵のリスト
フリーの敵のリスト

ってな感じで敵の状態ごとにIDのリストを返してくるような
ぱっと探しただけだと見つからなかったんだよねこういうの

ケミWIKIの横殴り対策みたいに4重にも5重にもif判定が重なってるの見るとね・・・

141(○口○*)さん :06/03/28 13:02
それと、無駄かもしれないが
移動中の敵もターゲットをちゃんと持って死んだりタゲはずれたら
きちんと0なり-1なりを返すようにしてほしいだとか
ホムも攻撃したらちゃんとATTACK_MOTIONになるようにしてほしいとか
ダメージモーションもきちんと取れるようにだとか
ヘルプデスクあたりから送っておかないか?

用は
GetVで取れる情報を動きがあるたびにきちんと更新汁!
ってことなんだが

142(○口○*)さん :06/03/28 13:10
それなら敵ID入れて優先度返してくれた方がいいな。
無視対象は0、ホム、ケミタゲってたら9とかね。

移動中のタゲは判定書いたからもういいけど、
ターゲットにされて「何をされたか」ぐらいは知りたいところだなぁ。

143(○口○*)さん :06/03/28 14:00
>>140
使えそうなライブラリー、作ってる人いますよ。
ttp://spaces.msn.com/dartymary/ 内、
ttp://www6.plala.or.jp/mahny/dl/roCharactorTable.zip

144(○口○*)さん :06/03/28 14:32
>>142
その優先度って人やケミによって結構変わるんだよね
いくら囲まれてもよける鳥使いはホムより主人の敵タゲってほしいし
梅ゼリーのようにHP高いのはいいが防御ステがだめだめならホムの周りから殲滅してほしい
こっちに向かっている途中の敵と画面内うろついてるだけの敵だったら
遠くても向かってきている敵をタゲってほしい
このリストの判定を並べてその順番で優先度をつける
ホムタゲリスト判定→居ればさらに優先すべき敵を選ぶ
↓居なければ
ケミタゲリスト判定→居ればさらに優先すべき敵をry
↓居なければ
向かってきてるリスト判定→居ればさらに優先すry
↓居なければ
うろついてる敵リスト判定->ry

見たいにして判定の順番で優先順位をつけていく
これにID渡してどこで引っかかるかで優先順位を返すこともできるね

145(○口○*)さん :06/03/28 14:51

function OnFOLLOW_CMD ()

--
if (MyState ~= FOLLOW_CMD_ST) then --ステータスが待機状態でなければ
MoveToOwner (MyID) --なんたらーして
MyState = FOLLOW_CMD_ST --待機状態にする
MyDestX, MyDestY = GetV (V_POSITION,GetV(V_OWNER,MyID))
MyEnemy = 0
MySkill = 0
TraceAI ("OnFOLLOW_CMD") --んでステータスが待機状態なら
else
MyState = STOP_CMD_ST --ストップしてしまえ。
MyEnemy = 0
MySkill = 0
TraceAI ("FOLLOW_CMD_ST --> IDLE_ST")
end

end

なんとなくこうしたらALT+Tを2回押すとずっとその場で待っててくれるようになった…。

146(○口○*)さん :06/03/28 15:19
ただ問題は、わかりやすさと引き換えに処理が多少重くなることかな。
AI()の呼ばれる間隔からすれば問題はないと思うんだけど
まぁ、いつの時代も処理的な最適化と論理的な最適化は往々にして排反事象にある。

>>143
お〜
帰ったら早速落としてみることにするよ

147(○口○*)さん :06/03/28 17:35
ちょっと気になった事が。
Move (MyID,x-5,y)

↑の場所にホムが移動しようとしたときに、
壁とかがあって動けない事がよくあるのですが、
この場合、そのプログラムの行は無視で次の行に?
それとも、そのプログラムの行で止まる?

そのプログラムは無視で次の行へ進むなら、
先に移動先をメモって置いて、その位置にいなかったら
別の場所に移動とかもできそうかなと。

148(○口○*)さん :06/03/28 17:46
>>147
止まらない。
あと、ホムが今いる場所に Move() しようとすると、
移動先に他人がいる場合と同様の動作をするね。

149(○口○*)さん :06/03/28 17:47
>>147
無視で次の行へと進んでく

150(○口○*)さん :06/03/28 18:30
local ikura = GetActors ()
for i,v in ipairs(ikura) do
if(GetV(V_HOMUNTYPE,v) == 1142) then
local ikuraX, ikuraY = GetV (V_POSITION,v)
end
end
画面内にイクラがいたらイクラの座標取得ってこれで間違ってるとこありますか?
うまく動いてくれない・・・

151(○口○*)さん :06/03/28 18:31
local

152(○口○*)さん :06/03/28 18:40
>>147 を見て気付いたんだけど、移動時のスタックを検出するには
  gHomStacking = (GetV(V_MOTION, gHomID) == MOTION_STAND) and ((gHomX ~= gHomDestX) or (gHomY ~= gHomDestY))
だけで良いのですね。
gHomX にはホム現在座標、gHomDestX には Move() に渡した引数を予め保存しておく。

153147 :06/03/28 19:16
なるほど、やはり止まらないのかthx
あとで考えて、プログラムしてみます。

154(○口○*)さん :06/03/28 19:39
>>147
確かにプログラム動作上は、Move()はその指定座標の進入可否に関係なく処理されるので、
座標管理で「移動できたかどうか」は判断できます。
ですが、注意しなければならない点が2つほどあるので、指摘しておきます。
#っていうか、147氏の書き方だと机上理論だけでやってるようにみえたので、現実の課題ってことです。

指摘1:Move()の結果移動できないケースには、
「指定セルが進入禁止」のほかに
「指定セルまでの移動経路の途中が進入禁止(要は壁向こうの通路を指定したケースなど)」
の可能性があります。なので、単純に
「移動できなかった==そのセルが進入不能」とはならないので注意。
まあ、移動を隣接セル限定にすれば回避できるかな。

指摘2:Move()は非同期動作です。
Move()を実施したからといって、ホムが指定地点にすぐ到着するわけではありません。
なので例えば
local oldX,oldY = GetV(V_POSITION, MyID)
Move( MyID, oldX+1, oldY )
local newX,newY = GetV(V_POSITION, MyID)
・・・と1関数内にずらっと書いても、まず間違いなくnewX==oldXです。
(プログラム1行実施するくらいの時間では、ホムが1歩あるけない)
監視する場所はきちんと考えないとダメですね。

155(○口○*)さん :06/03/28 20:10
移動の有無の分岐用にこんなの使って頑張ってますが色々ダメポ。移動座標関係がAIの中で一番比重が大きいような気がします

function LastPositionSave(id)
_local idX, idY = GetV (V_POSITION,id)
_LastMoveTime = GetTick()
_LastX , LastY = idX , idY
end

function LastPositionLoad (id)
_local isItNow = GetTick()
_if ( isItNow > 500 + LastMoveTime ) then
__local idX, idY = GetV (V_POSITION,id)
__if ( idX ~= LastX and idY ~= LastY ) then
___return true
__else
___return false
__end
_end
_return nil
end

156(○口○*)さん :06/03/28 20:17
色々突っ込みどころ満載で申し開きようも無し orz

157(○口○*)さん :06/03/28 22:20
移動と戦闘部分はまとめて再利用できるようにしたいとこだなあ

158(○口○*)さん :06/03/28 22:21
それぞれまとめて、ってことで。

159(○口○*)さん :06/03/28 23:52
Moveで移動できない座標を指定してるってのは、敵を殴りに
行くときだと思うんだが違うんかな?
俺の場合、下水で止まりまくるんで、座標Aにおける無視する
敵リスト作って対処したが現状問題出てない
あと、移動できないからってMove送りまくるとサーバー負荷とか
回線負荷が凄いことになりそうなんだが気のせい?

160(○口○*)さん :06/03/29 00:05
移動できない系は、いろんなケースで起こりますよ。
・基本的に、画面を直接クリックで無い移動では、いつでもリスクがある。
 ボスの周囲のランダム移動とか、緊急時のぐるぐる回転とか。
・ユーザーが意図的にいけない場所を移動先に指定しているケース。
・CHASE状態で、敵までの経路が壁にさえぎられているケース。
 (壁向こうの敵を対象に選んでしまって動けなくなっている)

本質的には「そこにはいけないんだよ」って教えることができれば
対処可能だと思いますが・・・敵については、とりあえず索敵範囲を狭めるだけで
だいぶ影響が小さくなると思います。
(壁向こうの敵に気が付かなければ問題にならない)

Move多用でのサーバー負荷は否定できないですね。
移動できないんだから、別の移動できそうな座標を選ぶとか、
そもそも移動をあきらめるとか、対処をするのがお行儀はよさそう。

161(○口○+) :06/03/29 00:16
ダブルクリック判定を作ろうとしているのだけれど、
同座標をALT+ダブルクリックすると、最初のMOVE_CMDだけ送られて
2回目のMOVE_CMDが予約コマンドリストに入らないのは仕様・・・??

/traceai + 基本AI で
コールホム → ケミの下のセルをALT+ダブルクリック → すぐ安息

++ TraceAI.txt 出力結果
OnMOVE_CMD
MOVE_CMD
OnMOVE_CMD_ST
OnIDLE_ST

おかげでダブルクリック判定がトリプルクリック判定に変わっちまったい・・・

ちなみに別の地点をすぐにALT+クリックした場合は
問題なくコマンド受け入れられましたとさ。

162(○口○*)さん :06/03/29 00:25
Move() 多用といっても、AI() の実行一回につき一回の Move() 程度なら、
例えば戦闘中には AI() 実行回数と同数の Attack() を送っていることを考えると
それほど気にする必要はないんじゃないかな?
もちろん、無駄なコマンドを送らずに済むならそれが最善ですけど。

163(○口○*)さん :06/03/29 00:48
>>161
同じことを以前にやった人がここに。
どうも、同じ座標の連続クリックはクライアントレベルで捨てられてるみたいです。
入力手段がやっぱり少ない(^^;;

164(○口○*)さん :06/03/29 01:23
移動不可セル対策はなかなかうまくいかない…

|||orz

165(○口○+)161 :06/03/29 01:54
>>163
やっぱり仕様ですか・・・ありがとです。

同じ座標の連続クリックは
1クリック目 → 受理
2クリック目 → 無視
3クリック目 → 受理
となるようなので、
開き直ってトリプルクリック判定として作っちゃうかなぁ・・・

166(○口○*)さん :06/03/29 06:59
>>161
予約コマンドとは「Alt + Shift + 右クリック」のことです。
Shift 無しの入力はどんなに連続入力しても常に GetMsg() で取得されます。
同様に Shift 入力は常に GetResMsg() で取得されます。

標準 AI では GetResMsg() の戻り値をリストに格納して
「予約コマンド」としてIDLE_ST で処理しています。
この機能がいらなければ GetResMsg() の戻り値を直接利用して
機能を実装することができます。

167163 :06/03/29 07:44
>>166
を、なんかIDが素敵(笑)

>>161
あ。161氏の言っている「予約リスト」ってそっちの話をしてるのか・・・
わたしの回答、ちょっとゆがんでるかも。
わたしが試したのは、
地面を2回「ALT+右クリック」した場合、1度目のALT+右はGetMsg()で取れるけど、
2度目は取れない、っていう話です。

168(○口○*)さん :06/03/29 09:59
一応補足しとくけど、TraceAI は同じ文字列送ると初回しか表示されないよ。
もしチェック用に吐き出してる文字列が一緒なら、変えて試してみるといいかも。

169(○口○*)さん :06/03/29 10:00
>>139
なるほど…。そういわれると確かに「敵がケミを攻撃したので、それに対して反撃」の動作でした。
特に手は入れてません。
インベが射程2だったのでインベした後、敵が近づいてきて攻撃を受けるまでのタイムラグだったみたいです。
これって「敵がケミを攻撃したので、それに対して反撃」のプロセスと「ケミが殴った相手を一緒に攻撃」って同居できるのでしょうか?

170163 :06/03/29 10:17
ID違うけど、163です。
>>168
とりあえず、TraceAI()の仕様情報さんくす。

で、それ、163&161氏向けの指摘でしょうか?
一応わたしのほうの確認では、TraceAI()のその仕様に影響される問題ではないです。
クリック後にフラグがたつこと/別ルートを通っていることを確認するために、
確実に違うTrace表示はでるようになっていました。

ある場所クリック→同じ場所クリックだとその(2回クリック用の)処理ルートを通らず、
ある場所クリック→その1セル隣クリックだと、その処理ルートを通る、という動作を確認済み。
なので、同じセルをダブルクリックすると、そのダブルクリックの2回目クリックは捨てられている、
と判断しています。
トリプルクリックは、わたしは試していません(^^;;

171(○口○*)さん :06/03/29 10:34
捨てられてるというか。
「ダブルクリック」はclick二回とは処理されないで
click + dblclick(だけ)となるっていうのがOSレベルでの仕様のはず。

マウス設定でダブルクリックの感度をシビアにしてから
「ダブルクリック」でclick二回拾えるか試してもらえる?
これでうまく拾えるなら、dblclickに化けたせいでAIに伝わってない
というのが確定する。

172163 :06/03/29 10:47
なるほど、その可能性はありますね。>OSレベルでCLICKがDBLCLICK
理解はしたが、今は出先なので確認できず。

173(○口○*)さん :06/03/29 10:56
単純な話、GetMsgで取れる情報は「コマンドを送ったか」しか記録してないんで、
AI()の実行より早く連打しても「クリックはされていた」という事は分かるが、「何度クリックした」しかは分からない。

AI()自体、AI()終了後150ms前後に呼ばれるため(うちの環境だと、最速で140msだった)
ダブルクリックのように早く連打しても、反応できないんでしょう。

-- テスト用空AI
TimeAI = 0
TimeMsg = 0

function AI(myid)
local time = GetTick() - TimeAI
TimeAI = GetTick()
TraceAI("AI : "..time)

local msg = GetMsg(myid)
if (msg[1] == 1) then --' Alt + 右クリック
local time = GetTick() - TimeMsg
TimeMsg = GetTick()
TraceAI("msg : "..time)
end
end

174(○口○*)さん :06/03/29 11:22
ATTACK_CMDとしてのALT+クリック→クリックとダブルクリックは受け付けてるから
クライアント側でダブルクリックの操作は捨てられてる可能性もあるかな
他にも、シーズ以外ではPCをALT+ダブルクリックしても効果はなく、
代わりにその座標でのMOVE_CMDが送られてくるしスキルをPCに使おうとしても無効だし。

175(○口○*)さん :06/03/29 12:05
とりあえずクライアントのインターフェースはきちんと公開してもらわないとなぁ

それこそ今の状態だとクライアントで使えるのに公開されてない関数までありそうな気がする

マニュアルの充実ってことで一部の例だけじゃなくてその手のリスト作って乗せろと要望出してきた

176(○口○*)さん :06/03/29 12:13
>>171
Windowsの話なら
ダブルクリックの動作はBUTTONDOWN→BUTTONUP→BUTTONDOWN→BUTTONUP→BUTTONDBLCLK
二回目のクリックが捨てられるなんてことはないよ。

177(○口○*)さん :06/03/29 12:28
ちょっと質問っす。
今AIをオブ指向に近づけようとしているのですが、
Luaの関数ってJavaScriptみたいにどこに書いてあっても
呼び出し時にビルドされるようなイメージで問題ないですかね?

一応自分で試しにデフォルトのAIでFunc AIを一番上の関数に持ってきましたが
問題なく動いてます。

あと、各状態関数をクラス化させるようなイメージで
各状態関数=1ファイルでまとめようと思っているのですが
参照ファイル増えると処理重くなります?

冒頭の参照って毎回呼び出されるのかな・・・?

178(○口○*)さん :06/03/29 12:54
参照ファイル数多くても、あんまり関係なさそう。
うちはすでに9ファイルくらいに分かれている<分けすぎ。

179(○口○*)さん :06/03/29 15:12
うちは既に21ファry

スクリプトは「ホム生成時」に AI.lua 先頭から終端まで実行されます。
その後定期的に AI() が呼ばれるため、AI() からの呼び出し先で
require していなければ「ホム動作中」にファイル読み込みはしません。

180(○口○*)さん :06/03/29 16:25
requireは内部で重複ロードのチェックをしてるから、たとえ
function AI(MyId)
  require "hoge.lua"
end
と書いても1度しか読み込まれないはず

18174 :06/03/29 16:45
>>179
負けた、20ファ(以下略)

>>74関連
いろいろアドバイスありがとうございます。

で、勘違いというかなんというか、
最初のうちは、死亡状態のモンスターのモーションが
DEAD>STAND>ATTACK(?)
のように、DEAD後に他のモーションを取っているTraceAIでの結果が
あったと思い込んでいました。
で、後日数種類のモンスターで確認してみたところ、
一度DEADになったら、消滅するまでDEADのままでした。
(DEADの前にSTANDがありうるのはこちらでも確認できました。)

現在、>>113のを参考に、
「ATTACK継続の判定にDEADならATTACKを止める」
と変更し、少し試してみたところ、現在のところ不具合は出ていません。

182(○口○*)さん :06/03/29 17:21
>>162
同じ事を考えたんだけど、Attack()を呼び出したとき、攻撃ディレイ中なら
何もしないとかのパケット送信の抑止制御がクライアントで可能なんだよね。
でも、Move()で別座標を指されたら無視するわけにもいかないから、
AI()が呼ばれる毎にMove()するようなのはやっぱり鯖への負荷になるかも
しれんと考え直して、ディレイを入れたりしてる。

一人分の負荷は微々たるものでも大勢集まれば脅威になりうるだろうし。

183(○口○*)さん :06/03/29 18:02
この前のメンテ延長ネットワーク調節はMove連打の性かもしれんね
グローバル1個追加して10ループに1回Moveしてる
MoveToOwner使わなければこれでも十分等速っぽい

184(*○口○)さん :06/03/29 19:17
>>183
やぁ俺
4ループに1回でやってる
ついでにOnMOVE_CMD_STに4ループでMOTION_STANDならFOLLOW_STになる様にも組んでる

185(○口○*)さん :06/03/29 22:24
Moveのラッパーつくってそん中でTickとって、前回実行時から600ms以上
経ってないとMoveは実行されないって感じで組んでる
環境によって違うだろうけど750msにしたら等速にならなかった

186(○口○+) :06/03/30 00:24
MOVE_TIME = 0

function R_Move( x,y )
  if GetTick() >= MOVE_TIME then
    Move( MyID,x,y )
    MOVE_TIME = GetTick() + 600
  end
end

・・・な感じでOKなのだろうか。ラッパーって何なのか良くわからないけれど。

187(○口○*)さん :06/03/30 00:36
say Yo!みたいなやつだとおもう

188(○口○*)さん :06/03/30 01:19
手動でスキル使用してみたら少し変わった感覚があったので
今週のパッチで何か変化したのか軽く試してみたら

手動で攻撃スキル使用する時の射程情報が鯖から返ってきている
ケミスキル使用してしまうの穴が塞がっている

そんな感じの動作だったので
簡単な検証しかしていないけどここに報告

189(○口○*)さん :06/03/30 01:28
>>188
試してきた。

>手動で攻撃スキル使用する時の射程情報が鯖から返ってきている
画面端の敵キャラにムーンライト可能。

>ケミスキル使用してしまうの穴が塞がっている
PP使えました。

結論:気のせい

190(○口○*)さん :06/03/30 01:30
射程情報は鯖じゃなくクライアントかな?・・・
とりあえず

手動でやった際に
ターゲットの隣に移動⇒スキル使用・・・だったのが
ある程度の距離なら即座にスキル使用するようになった

公式のデフォルトAIでもこれは確認した

191(○口○*)さん :06/03/30 01:37
>画面端の敵キャラにムーンライト可能。
射程最大の制限じゃなく
IsInAttackSightの判定に関したほうの話

>PP使えました。
こっちは気のせい確定か・・・

192(○口○*)さん :06/03/30 01:41
V_SKILLATTACKRANGEが実装してるかも?ってことね。

確認してきました。
通常攻撃時もスキル攻撃時も戻り値は1のみ。まだ未実装ですね。

193(○口○*)さん :06/03/30 01:43
じゃあそっちも気のせいか・・・
AIのフォルダにあるファイル見直してみよう

194(○口○*)さん :06/03/30 01:50
それにしても V_EATEN とかが欲しいな
OnEAT_CMD や Eat コマンドは殺していいけど空腹状態をもっと早くわかりやすく表現できる方法が欲しい
今のところ主人の無反応時間から推測するしかないから怖いわ

195(○口○*)さん :06/03/30 08:03
起きてるならたまに情報窓だせばいい。寝落ちでホムロストは、むしろ当然のペナルティだと思うし。

196(○口○*)さん :06/03/30 08:30
MobDataの人のライブラリすごくお世話になってるんだけど
playerjobdata.luaのスペルミスは直したほうがいいと思うw
AcoliteとかMarchantとかWizerdとか

197(○口○*)さん :06/03/30 08:54
あと、シーズモードだとプレイヤーでも IsMonster == 1 になるから
IsPlayerの中でIsMonsterを調べるのは
ADとか行くと不具合が出るんじゃなかろうかと思った

198(○口○*)さん :06/03/30 08:59
>>183-186
うちは実測したら大体120msでAI()が呼ばれるようだったから5回にしてるな
これは画面切り替えで落ちる対策にもなってるはず?

あれって切り替わって生成時の呼び出しで暗転中に移動しようとしてるのが原因だと思う
ステルス対策のときに画面切り替え後すぐに動くとおちたっしょ?
あれが短く修正されてるけどいまだ有効だから
MAP移動→ホム再生成→すぐAI()呼ばれる→常にMove連打→まだ暗転中→あぼーん
って状態なんだと思う

再生成時1秒待機してから飛び出すとかそういう処理作ってもいいんだろうけど

199(*○口○)さん :06/03/30 10:22
|-')ジーー>>196,197
|')つttp://proxy.f3.ymdb.yahoofs.jp/bc/44183003_d9ee/bc/playerjobdata.lua?bcqdzKEBFav1oTk9
|ミ

_| ̄| ((○<センター英語3*てn(ry

200(○口○*)さん :06/03/30 19:36
>>198
local x, y = GetV (V_POSITION,GetV(V_OWNER,MyID))
if (GetDistance(x,y,MyDestX,MyDestY) > 3) then
  MyDestX, MyDestY = GetV (V_POSITION,GetV(V_OWNER,MyID))
  Move (MyID,MyDestX,MyDestY)
  TraceAI ("FOLLOW_ST -> FOLLOW_ST")
else
  TraceAI ("MOTION_MOVE NoMove")
  TraceAI ("FOLLOW_ST -> FOLLOW_ST")
end

俺はこんな感じにしてる。
これなら個人の環境にも依存しないし、毎回ticをとる必要もないしな。

201(○口○*)さん :06/03/30 19:44
>>198
呼び出し直後って座標かぶってるから敵がいなきゃ移動ないんじゃ?
狩場での問題ならわかるけど町中でも起きるんだよねこれ

202(○口○*)さん :06/03/30 20:20
思うんだが、

自動PPが出来るならば、自動安息も可能?
空腹度取得できないから無意味かもしれないが・・・・

203(○口○*)さん :06/03/30 20:25
ポーションがない場合には自動PPをしないようにできますか?
うっかり忘れてると,ものすごい勢いでスキル使用失敗が_| ̄|○

204(○口○*)さん :06/03/30 20:41
>>202
今「寝落ち防止」って言われてるAIのコードも
空腹じゃなくて主人が指定時間以上まったく行動していないってのをトリガーにしてるだけだから、
同じ条件で安息スキル使わせるのだけならいけるんじゃないかと思う。


が、何度も言われている通りAIで「ケミスキル」を扱うことは(以下略

205(○口○*)さん :06/03/30 20:43
あ、あと安息はスキルだから
主人がスキルを使えない状態にある場合は無意味になってしまう。

座ったままとか露店中とかチャット開設中とか。

206(○口○*)さん :06/03/30 20:54
ヒント:HPの変動
|ミ

207(○口○*)さん :06/03/30 21:13
tail for win32
http://tailforwin32.sourceforge.net/

windows用のtailらしい
TraceAI眺めるのに便利そう?
課金切れてるのでまだ確認はしていないが…

208(○口○*)さん :06/03/30 22:24
HPの増減ってあてになるのかな?
テロとかで運悪く生き残った場合に自己回復してるとエサやってると誤認されそうだけど

209(○口○*)さん :06/03/30 22:30
>>208
>>206>>203宛だとおもうヨ

210(○口○*)さん :06/03/30 22:32
あ、そうか。失礼した

211(○口○*)さん :06/03/30 23:20
L88Vitケミで鳥を使役しています。おすすめのAIを教えてください。
それとも狩場や狩り方、装備やLuaの知識などで変わってくるものなのでしょうか。
テンプレは見ました。
すべてのAIを設定変えながら使ってみるのがめんどそう。

212(○口○*)さん :06/03/30 23:26
自分用にカスタマイズしていけないのであれば、
どれ選んでも大して変わらないと思ってる。

213(○口○*)さん :06/03/30 23:34
GUIで設定できるAIもあった気がしなくもない
iniファイル持っててそれ編集するタイプのが多そうだけど

214(○口○*)さん :06/03/30 23:40
>>211
最初は欲しい機能があるのを選んで、不満が出てきたら他のを試してみるなり
自分で手を入れてみるなり。

215(○口○*)さん :06/03/30 23:43
まぁ、この話題はどっちかっていうとAI雑談スレ向けかな。
そっち移動して聞いてみるといいよ


って向こうにも似たような書き込みあるな。

216(○口○*)さん :06/03/31 00:24
>135
ttp://www.mmobbs.com/uploader/files/122.zip
自動フリートムーブを簡易で実装

ただし
こっちのホムは鳥じゃないので動作確認が万全じゃないので注意


主人と一緒に攻撃の判定はまだよくわかってないので未実装

217(○口○*)さん :06/03/31 03:03
イクラ回避コード作っても画面外に行ったら反応が('A`)

218(○口○*)さん :06/03/31 03:29
>>217
どういう意味だ?

219(○口○*)さん :06/03/31 03:58
>>217
イクラ発生→イクラ移動範囲+イクラ発動範囲分移動→画面外反応消え('A`)
ってことか?

220(○口○*)さん :06/03/31 06:00
>>216
俺は、フリートムーブはSP消費激しいから使ってないな。
SP回復力に対して、持続時間が短いorz
代わりに、自動月光使ってる。
HP減って敵から遠くに離れても、遠距離月光を自動でして
くれたりするから、いい感じなAIになってきてる。

221(○口○*)さん :06/03/31 07:22
>>216
お世話になります。
氏は鳥以外でしたか。
応援していますので頑張ってください〜。

222(○口○*)さん :06/03/31 10:36
>>217
・ホムが画面外まで逃げて動かなくなってアボーン
・イクラが画面外で移動したら、正確な範囲取れなくてアボーン
・イクラが画面外で爆発したら、そもそも情報取れなくてアボーン

さあ、どれだ

どうでもいいけど、イクラ回避コード入れとくと、
周囲をイクラで囲まれた場合おろおろしそうで、ちょっとほくそえましい。(←何故か変換でk(略

223(○口○*)さん :06/03/31 14:58
ちょっと調べたいことがあるのですが、出先なので動作確認できない状況。
どなたか情報をもっていたら、教えてください。
GetActor() で取得できるobjectのIDについて。

そのobjectがプレイヤーキャラだと、そのIDは一意ですよね?
そのobjectがホムンクルスだったら、どうでしょう?

気になるポイントは、以下のような状況。
・ホムが(ケミと一緒に)テレポートした場合、IDは同じ?変化?
・ホムが一度死んで、リザレクションされた場合、リザレクション前後でIDは同じ?変化?
・ホムが(ケミと一緒に)ログアウト・ログインした場合、その前後でIDは同じ?変化?

224(○口○*)さん :06/03/31 15:55
ホムはID可変のはず

225(○口○*)さん :06/03/31 16:06
>>224
了解。さんくす。
ってことは、友達登録からホムIDも避けなきゃならんな。

226(○口○*)さん :06/03/31 17:30
AIとは違うけど、mobdata.lua で効率検索することを思いついたので投下。
でも、検索結果を見ると既出だからあまり意味ないかも。

-- 「ホム壁育成Mob検索」
-- mobdata.lua @ http://briefcase.yahoo.co.jp/kulus_project
-- の末尾にこのプログラムを追記して、
-- http://wave.prohosting.com/hammm/luacgi/runlua.cgi
-- 上記サイトで実行すると、育成効率の良いMobを検索できます。

local ExpPerMHP=35 --EXP/MHP比率〜以上のMob (例)ポポ23 メタリン55 黒蛇40
local Hit100=120 --必中Hit〜以下のMob (例)ポポ48 メタリン61 黒蛇106
local MaxLv=50 --モンスターレベル〜以下のMob (例)メタリン26 黒蛇43
local MinLv=10 --モンスターレベル〜以上のMob (例)ポポ14

-- 上記変数の定義を mobdata.lua の頭に置くと変更が楽になります。

local Count=0 --条件HIT数(変更不可)
local i=1001 --MobID開始(変更不可)
local j=1685 --MobID終了(変更不可)

print("検索条件 MobLv"..MinLv.."〜"..MaxLv.." 必中"..Hit100.."以下 EXP/MHP比率"..ExpPerMHP.."%以上")
print("※AGI型ケミはFlee95%重視、VIT型ケミは低ATK重視。")
while (i<=j) do
if (MOBDATA[i] ~= nil) then
if (ExpPerMHP*0.01 < MOBDATA[i][M_V_BASEEXP]/MOBDATA[i][M_V_MAXHP]) and (Hit100 >= MOBDATA[i][M_V_HIT]) and (MaxLv >= MOBDATA[i][M_V_LV]) and (MinLv<= MOBDATA[i][M_V_LV]) then
print(MOBDATA[i][M_V_NAME].." Lv"..MOBDATA[i][M_V_LV].." Exp"..MOBDATA[i][M_V_BASEEXP].." MHP"..MOBDATA[i][M_V_MAXHP].." ExpPerMHP"..math.floor(MOBDATA[i][M_V_BASEEXP]/MOBDATA[i][M_V_MAXHP]*100).."% Hit"..MOBDATA[i][M_V_HIT].." Flee"..MOBDATA[i][M_V_FLEE].." Atk"..(MOBDATA[i][M_V_ATKMAX]+MOBDATA[i][M_V_ATKMIN])*0.5)
Count=Count+1
end
end
i=i+1
end

if (Count==0) then
print ("検索条件に一致するMOBが見つかりません。必中HITは足りないことを前提に入力すると吉。")
end

227(○口○*)さん :06/03/31 22:03
すっげぇ理解できない初心者にわかるようにお願いできませんでしょうか

228(○口○*)さん :06/03/31 22:11
>>226
cgi上でluaのテストできるんか、面白いな
そんなサイトあったのか

229(○口○*)さん :06/03/31 22:24
>>223-225
一人じゃ実験できなさそうなので便乗質問。

GetV(V_OWNER, 他人のホムのID)
で、そのホムの主人のIDを拾うことってできる?

これができるなら事実上、ホムの不変なIDを得ることができるよね。

230(○口○+) :06/03/31 22:27
>>229
GetV( V_OWNER,MyID ) って確か、第二引数がなんであろうと
自分の主人のID返すんじゃなかったでしたっけ。
どっかでそんな記事を見た記憶が。

231(○口○*)さん :06/04/01 00:01
公式のAIマニュアルで、第二引数には意味がないって書いてあったな

たとえ
GetV(V_OWNER,0)
でも自分の主人のIDが帰ってくる、って。

232226 :06/04/01 01:49
>>227
趣旨は、せっかくmobdataという便利なデータベースがあるので、
これを利用して自分のステでレベル上げしやすいMobを抽出することです。
実行環境の構築を省略できるので、ブラウザでテストできるサイトを使ってみました。

当然、mobdata.lua が定義されたあとに実行しないと動かないので、
このプログラムは末尾に追加してやる必要があります。
ただし、検索条件の変数定義だけは頭に書いた方が頻繁に変更しやすいです。

ホムの育成に必要なのは何よりホムのHITと、Mobの柔らかさなので、
ケミがAGI型か、VIT型かはあえて問わず、検索結果から判断するように
してみました。

余談ですが、mobdataにアイテムドロップ率とアイテムの相場データベースを
追加すれば金銭効率も検索可能になって、うわ超便r……夢を見過ぎた。誰が作るんだ。

233(○口○*)さん :06/04/01 02:40
斜め読みかつ二行飛ばしに読んだけど、

要は

・mobdata.luaをホムAIの一部としてではなく、純粋にMOBのデータベースとして使う。
 もちろんROのクライアントがなくても動く。ホムの動作には関係ない。

http://wave.prohosting.com/hammm/luacgi/runlua.cgi のサイト上に、>>226のコードを仕込んだ
mobdata.luaのソースを与えることで実行できる

・今時点のホム育成に適正なMOBを検索できる。
検索する際の条件は以下の通り。

    EXP/MHP比率が〜以上
    必中Hitが〜以下
    mobレベルが〜以下
    mobレベルが〜以上

・mobdata.luaが最新可されれば、そのmobdata.luaを使用することで、最新の効率情報が検索できる

ってことかな。AIの一部として組み込んで、クライアントで動かすと勘違いする人が多いだろうから、
そこは強調して明言しておいたほうがいいのかもしれない


もっとも、俺の↑の読み自体がまったくの的外れな可能性も80%ほどはあるが。

234(○口○*)さん :06/04/01 04:17
>>226,232
・ホムはmobと同じなので最大95%HIT
・>226の検索式に敵DEFが考慮されていない
・>233の言うとおりmobdata.luaを貼り付けるくらいなら中に入れておけばいい
・最適mobの抽出はなにもLuaでやる必要はない、扱いやすいプラットフォームで処理すればいい
・自分の知る限りドロップ率があるサイトは【RO2】1ッ箇所のみ
・アイテムの相場は鯖ごとに格差がデカイので「RAG.D Project」が使っているRO店価格調査隊へのリンクのみが無難

・Luaでやるならdropitem.luaの様に分離すること


未来予想図?
・外部(cgi等)にmobデータ+ドロップデータベース
・外部データからLua用データへの出力ページ
・Luaデータのミス報告フォーム(mobステ+ドロップ)
・Luaデータのミス編集インターフェース

・外部データを利用したMOBの配置MAPページ、属性やFLEEHIT等検索ページ、RO店価格調査隊へのリンク等


まぁ俺はROをプレイしてくる
ガンガレ

235234 :06/04/01 04:24
スマン、>>233のMOBのデータベースをSQLとかと取り違えてたorz
最初の3っつ目は未来予想の方にでも・・・

236(○口○*)さん :06/04/01 05:59
Lua が多バイト文字コードを考慮していないため、
文字列中の \ が誤認識されるいわゆる「能力表」問題が発生します。
mobdata.lua ではソヒーの'ソ'などが該当します。
この場合SJISで'ソ'の2byte目が \ にあたるため、以降の文字が化けます。
また、末尾に'ソ'がつく文字列を定義するとコンパイルエラーとなります。
(文字列を囲う'や"がエスケープされるため)

対策としては 'ソ\ヒー' または [[ソヒー]] のように書くか、文字コードの変更が必要です。
文字コード変更の場合 UTF-8 がお勧めです。

# [[string]] は中身がまったくエスケープされない文字列定義方法です。

237(○口○*)さん :06/04/01 07:55
それは↑の実行サイトでの話?ホムAIの中では気にしなくていいんかな?

238(○口○*)さん :06/04/01 09:58
汎用性考えると# [[string]] が無難なんじゃね?grepで一括書き換えできんかな

何気にメモ帳ですらUTF-8には対応してるんでそっちでも良いけど
Roクライアント側で何か問題起きなければね

Roの方では純粋に8bitづつでしか見てないんだっけ
2バイト文字コード中にエスケープコード含んで無い文字セットなら問題起きないかな

239(○口○*)さん :06/04/01 10:03
>>237
多分構文解析の時点で止まる
mobdata.lua単体じゃ問題起きて無いけど
末尾がソで終わる敵が存在してないだけだね

今でも名前取得しようとするとバグった名前が返ってくるんじゃないかな?

まぁ、対策しといた方がいいと思う

240(○口○*)さん :06/04/01 10:32
>>230-231
できないのか。ィェァ補助とかもできそうと思ったのに残念。
でも公式マニュアルに載ってたっけ?見落としてたかも。

>>238
[[string]]
#はいらないよ。

--[[ … ]] 形式のコメントは、--直後の文字列リテラルを無視する
ともとれる。というかきっとそういうパースをしてるんじゃないかな。

241(*○口○)さん :06/04/01 11:52
>>240
主人が一定時間移動をせず、スキルが発動しない場合(露店、座り)イクラに近づくとか別な補助になるかな・・・・
現状ある寝落防止コードにexitが入っているならイエアはしなくても平気なんだろうけどね

>エスケープ問題
工体AIでモンスター名が攻撃判定に使われてしまっているのと
文字化けの苦情がまだ一つも無いので、今の所は現状維持かな〜と
元々モンスター名称は「人間」が見てそのIDがどのmobか分かるように必要だっただけで
ホムには名前なんて関係無いから文字化けだけなら別にいいかな〜とか(ぇ

対応済みの物も用意しては置きますが工体AIから名称チェックが消されるまでは
一応、未対応が正式、対応済みが次期正式という扱いになります。

ホムンクルス用モンスターデータライブラリ(次期正式版)
mobdata.lua
http://briefcase.yahoo.co.jp/kulus_project
http://proxy.f3.ymdb.yahoofs.jp/bc/44183003_d9ee/bc/%bc%a1%b4%fc%c0%b5%bc%b0%c8%c7%cd%bd%c4%ea.lua?bcf4eLEBJHpQlG2D

242(*○口○)さん :06/04/01 11:53
h取るの忘れたorz

243(*○口○)さん :06/04/01 12:00
連続スマンorz
mobdata.luaじゃなく次期正式版予定.luaです。

それと工体さんにゴニョゴニョしに行くのはお門違いなので
気づいてくれるのを生暖かく見守ってください

244(○口○*)さん :06/04/01 12:30
local preSP = GetV (V_SP, id)
SkillObject (id, level, skill, target)
local afterSP = GetV (V_SP, id)

みたいにスキル使用前後でSP取得してスキル使用が成功したか確認したかったんだけど
これ、preとafterが同じ値返ってくるのな

何らかの方法でwaitかけないと駄目ぽ



スキル使用前にSP残量とスキルディレイチェックさせる方が無難かねぇ

ぶっちゃけ手動でスキル使用される可能性考えるとディレイ管理は物凄く無理な気がす
鳥の攻撃なんかはスキル使用をイベントで取得できるけどな……

245(○口○*)さん :06/04/01 12:57
>>244
Attack や SkillObject や Move などのホムに行動させる命令は同期してないからね。
次行に移っても「命令を送った」だけで「行動が済んだ」わけじゃないから
ある程度のタイムラグを想定して別に状態取得しないといけない

246(○口○*)さん :06/04/01 14:02
スキル使用命令前後じゃなくて、タゲ見つけて攻撃しはじめた(タゲID変わった)ときに保存したSP量から減ったか、でなんとか動いてる。
減ったらまたそれを基準SPに、って感じで。

247(○口○*)さん :06/04/01 14:11
もちろんスキル使った直後には減らないけど、次にスキル使うまでには減ってるから、
「MOBのHP/1000」回だけスキルを使う、って使い方してる分には問題なさげ

248(○口○*)さん :06/04/01 18:15
>244
>鳥の攻撃なんかはスキル使用をイベントで取得できるけどな……

って、そもそも現状のホムスキルでイベントで取得できないスキルってあるのか?

249(○口○*)さん :06/04/01 18:23
>>248
リーフの緊急回避、羊のキャスリン・ディフェンスあたり

ここらへんはGetMsgでメッセージ飛んで来ないから
AI側で手動で使用されたのを判別できないんじゃなかった?

ターゲット非指定のその場発動スキルの類全般がそうだって聞く

250236 :06/04/01 19:00
じつはうちのAIでも名前指定でIgnoreテーブルとか作成しているので、
それでトレース中に文字化けに気づいたわけです。
ただし、configファイルもLuaスクリプトとして記述してある場合、
config 内の文字列も同様に化けるのでLuaでの比較はちゃんと一致します。:)

mobdata.lua の中の人、対応ご苦労様です。

251(○口○*)さん :06/04/01 21:46
>>248
鳥がムーンライトのみ、スライムはカプリスのみ
幼女と羊はわからん

252(○口○*)さん :06/04/01 22:25
幼女はどれも取れないでっす。

253(○口○*)さん :06/04/01 22:31
ユーザー操作起因でホムに与えられる操作(GetMsgで取れるイベント)は、以下のものだけ。

1. 地面を「ALT+右クリック」。
パラメータとしてクリック座標。
標準AIでは、移動に割り当てている。

2.敵を「ALT+右クリック」2回
パラメータとして、敵のID。
標準AIでは、敵への通常攻撃を割り当てている。

3. 「ALT+T」
パラメータなし。
標準AIでは、ホムの「通常」「待機」モードのトグル切替に用いている

4. ホムの対象指定スキルを選択して、対象クリック。
パラメータとして「対象のID」「スキル種類」「スキルレベル」
該当するのは以下のホムスキルのみ。つまり、アミストルとリーフではありえない。
 ・フィーリルの「ムーンライト」
 ・バニルの「カプリス」


かつ、上記の1,2については、+SHIFTのバリエーションがある。
ただしこれはGetResMsg() で取るだけで、内容は上記1、2と同じイベント。
1+. 地面を「ALT+SHIFT+右クリック」。
パラメータとしてクリック座標。
標準AIでは、移動予約(他の行動がすべて終わってから移動する)に割り当てている。

2+. 敵を「ALT+SHIFT+右クリック」2回
パラメータとして、敵のID。
標準AIでは、攻撃予約(他の行動が全て終わってから攻撃)を割り当てている。

254(○口○*)さん :06/04/02 01:30
>>253
「ALT+SHIFT+右クリック」は、
移動予約と攻撃予約、兼用じゃないか?

255(○口○*)さん :06/04/02 01:34
>>253
敵を「Alt + Shift + 右クリック」は2回ではなく1回。

>>254
地面対象と敵対象は別のコマンドが返されます。

256(○口○*)さん :06/04/02 01:43
mobdata.lua で以下のように「MOBDATA」が繰り返されるのが無駄に思える。
MOBDATA[1001] = {...}
MOBDATA[1002] = {...}

以下のように変更しませんか?
MOBDATA = {
[1001] = {...};
[1002] = {...};
...
}

いや趣味の問題なんですけどね…。

関係ないですがテーブルのキーを文字列とするとき、
例の文字コードを考慮すると table[ [[keyname]] ] とか書くことに…。
手前にスペース空けないとコンパイルエラーになります。(後ろはつめて可)
もっとスマートに書きたいよ… orz

257(○口○*)さん :06/04/02 02:31
>テーブルのキーを文字列とするとき、例の文字コードを考慮すると

2byte文字のリテラルでアクセスする事態そのものが
おかしい気もする。どんな状況?

258(○口○*)さん :06/04/02 02:40
あと>>238
Lua自体は「いかなる8ビット値も含むことができる」から、
エスケープシーケンスさえ回避できれば問題ない。
ROクラはLuaのstring型を扱わないから、問題はLua環境の中で閉じられる。

というわけでluaファイル全部の文字コードをeuc-jpあたりにすると
いうのも正解。試してないけど。

259(○口○*)さん :06/04/02 02:52
>>257
テーブルをハッシュとして使う時。

ついでにそれをシリアライズしてファイル出力とかしてたり。
無駄に汎用的にしようとするのは悪い癖ですが。

>>258
euc-jp でもいいけどやっぱり UTF-8 がいいなぁ。

260(○口○*)さん :06/04/02 04:18
ちょっと質問です。
移動コマンド処理を、予約リストを使わずに行うように変更している最中です。
予約リストの代わりに一時変数に格納してやってるんですが、少し疑問が・・・。

デフォルトではホムの現在地と移動先は15セル以上であれば、半分に割って移動を2回行うようになってますよね?
これはサーバー処理の仕様上、長距離の移動を認めない。みたいなことになってるんだと思うのですが
半分に割った値が更に15セル以上の場合はどうなるのでしょう・・・?
(つまり最終目的地と現在座標が30セル以上はなれているパターン)

261(○口○*)さん :06/04/02 04:22
>>260
脊髄反射レスしてみるが、30セルの移動指定って可能か?
視点を寝かせれば、カーソルはそこまで出るが
クリックしても移動不可能だと思うぞ。

262(○口○*)さん :06/04/02 04:27
>>261
なるほど。
根本的にクリック不可能なわけですね。
であれば問題ないのか・・・。

ソースを見直してて不思議に思ったので、質問してみました。
ありがとうございます。

263(*○口○)さん :06/04/02 06:51
>>260-262
15マス制限を外してホム現在地点を含め24マス先なら1クリックで移動しました。
画面外に出てしまってもクリックした地点に移動はするようです。
但し場所によるので移動しない場所もあり・・・17〜19マス程度なら移動してくれます。

24マス移動は
ルーンミッドガッツ王国の首都プロンテラ(prontera) : 134, 292
ルーンミッドガッツ王国の首都プロンテラ(prontera) : 134, 315
の2地点間で出来ました。
一列左では短くなる等、理由その他全て不詳ですが^^;;

264(*○口○)さん :06/04/02 07:12
追記
上のは半分に割って移動を2回行わないときの最大移動距離です。
30マス以上離れた場所でもALT+右で座標は送られてきますから移動は出来ると思いますよ
一回のMoveで17〜19程度(直線)なのでその倍までは行けるかと・・・・課金切れで試せず^^;

265(○口○*)さん :06/04/02 09:57
>>259
そりゃわかるんだけど、変数を経由すればいいじゃない。
日本語の文字列リテラル(ハードコーディング)で直接的に
アクセスする状況が、そもそも作法よくないんじゃないかという話。

あとeuc-jpを使えとは言ってないし、>>256もだけど
オマエの趣味などしらんがな(・ω・`)

266(○口○*)さん :06/04/02 10:23
ケチつけるだけなのもあれだからいちおう。

table = { ["日本語でOK"] = "data"}
setmetatable(table, {__call = function(s,v) return s[v] end})
table[[日本語でOK]] -- table([[日本語でOK]])と同じ

267(○口○*)さん :06/04/02 11:10
別にUTF-8だろうがeucだろうが好きなコード使えばいいだろ。
個人的に汎用的な作りにするのは勝手だが、
別に仕事でチーム開発してる訳じゃないし、
文字コードって何みたいな人もいるんだから、
コーディングルールとか提唱するだけ無駄。

技術者の陥りやすい罠だが、
技術者の使いやすい≠素人の使いやすい
って事は憶えておいたほうがいい。

268(○口○*)さん :06/04/02 11:32
でもまぁ、素人が扱った時に要らんエラーを出さない為には
ある程度は統一する方が無難っちゃあ無難だけどな

どっち使うかは別の話だが。

269(*○口○)さん :06/04/02 12:43
あんまり素人連呼するのもどうかと思うんだけど、そろそろ止めない?
公式で配布しているのに合わせればいいじゃない>メジャー配布AIもそうだしね

>>256
各mobデータの末尾、セミコロンでいいんだっけ?
「高読込み速度、低容量、上位互換」であればチョコチョコ変えて行きますよ〜

■kulus_project情報
・mobdata.lua var.2006/04/02
エスケープ対策済みの物に差し替えて置きました。
・playerjobdata.lua var.2006/03/30
スペルミスとGetPlayerClassのミスを修正、
IsPlayerの中でIsMonster使わない様に変更しました。

270(○口○*)さん :06/04/02 13:01
>>269
そこはカンマもセミコロンも同じ。
特に理由がないなら、違和感のないカンマが無難。

271(*○口○)さん :06/04/02 13:53
■kulus_project情報
・mobdata.lua var.2006/04/02
軽量化の物に差し替え、ついでにX_name系を少し修正しました。

いい加減ちゃんとした配布サイト作らねば('・ω・`)

272(○口○*)さん :06/04/02 20:41
>>263-264

ありがとー。

更に質問なんですが、っていうか既出なんだろうけど
デフォルトで用意されてる関数のほとんどが引数にホムIDを
使うみたいですけど、基本的に不要ですよね?
あと、処理毎に座標取得とかしてる部分って必要なときだけで
済ませたほうがパフォーマンス向上するんですかね?
(この程度の処理なら特に体感で遅くなることはないと思いますが・・・)

273(○口○*)さん :06/04/02 23:44
>>272
微妙に誤解しそうな内容だけど、例えば元AIの
function GetMyEnemyA (myid)
・・・っていうのを、myid==ホムID固定なんだから初めからグローバルでMyIDみたいにしておいて、
function GetMyEnemyA ()
・・・っていう定義にしても大丈夫?っていう質問だよね?

確かにその通りではあるんだけど、一般にプログラムを組むときはできるだけ
グローバル変数は使わないようにするのが「お行儀がいい」ってされてます。
いろんな理由があるけど、まあデバッグやメンテ性の問題が大きいです。

パフォーマンスについては、もちろん不要なことはやらなければ、それだけ負荷は小さい。
だけど、よほどとんでもないコードを書かない限り、このAIのレベルならそんなにひどい
負荷にはならないと思われます。

どっちの点についても、最後は自分の趣味のレベルでいいんじゃないかと。
まあプログラムっていうのは往々にして、後から(何ヶ月かしてから)見ると
自分で書いたものでも訳わからなくなってることが多いので、あんまり省略しすぎたり
前提条件を増やしたりすると、困ることも多いよ・・・
と、古くからのプログラマのコメント(^^

274(○口○*)さん :06/04/03 10:03
C言語の、
Char Str[10];
みたいな配列の書き方を、ルアでしてみたいのですが、
これはルアだとどんな感じになるのでしょうか?
ルアのマニュアルみても、よく分かりませんorz

275(*○口○)さん :06/04/03 10:33
>>274
Array = {} -- 宣言
Array[1] = 25 -- 代入
Array2 = {1,2,3,4} -- まとめて宣言1
Array3 = {[1]=25,[2]=30,[3]=35,[4]=40} -- まとめて宣言2

変数にChar等型宣言は無い、値が型を持つ
Luaの配列、Array[n]はn=0,1,2,3...ではなくn=1,2,3,4...である点に注意

276(○口○*)さん :06/04/03 10:57
>>275
なるほどthx
C言語に慣れてるから、ずっとn=0,1,2,3...だと思ってたorz

277(○口○*)さん :06/04/03 12:20
#define Char char

278(○口○*)さん :06/04/03 16:39
Luaは全部の変数がVBやC#のvariant型見たいなものと思えばいいね
使い方を間違わなければ便利な型なんだけど
全てがこの型で暗黙的変換を多用してるようだとバグの温床になりやすいんだよね・・・

279(○口○*)さん :06/04/03 16:48
>>278
だな。MyIDとかさ・・・文字列なのか数値型なのか問い詰めたいほど命名規則がなむ。
ROのバグが多い原因って、この手の単純ミスが多そうだ

280(○口○*)さん :06/04/03 17:09
宣言してない変数でもエラー出さないしな。
定数のスペル間違えてて、if 文で nil 返してたのにしばらく気付かなかったとかある。

281(○口○*)さん :06/04/03 18:20
いちおうLuaはLightweight Languageに分類されるはずだし、
そのへんがルーズなのは悪いと思わないけど。

ただ>>280のために、Perlのuse strict;やRubyの「一度しか使われて
いない変数」への警告みたいなのがほしいね。

282(○口○*)さん :06/04/03 18:58
>>274
Lua 標準ライブラリの table ではキー n が存在すればそれを要素数として扱っています。

array1 = {1, 2, 3, 4}
→ 4 == table.getn(array1)
array2 = {n = 10}
→ 10 == table.getn(array2)

その table が RO の Lua にはないわけですが…。
table を実装しなおしてる人が前レスでいたはずです。

unpack と arg は上記 n に対応しています。

function getn(...) return arg.n end
array3 = {n = 5}
→ 5 == getn(unpack(array3))

283(○口○*)さん :06/04/03 20:22
>>280-281
これ使えるかな?

http://hammm.dw.land.to/lua/
の、「Lua 明示的グローバル変数宣言モジュール」

284(○口○*)さん :06/04/03 20:54
function AI(myid)の、

-- 状態処理
if (MyState == IDLE_ST) then
OnIDLE_ST ()

(中略)

elseif (MyState == FOLLOW_CMD_ST) then
OnFOLLOW_CMD_ST ()
end

このへんの書き方が、無駄に分岐判定多くてキモいと感じた人はいないだろうか。


-- ステータス関数テーブル
StateFuncTable = {}
StateFuncTable[IDLE_ST] = OnIDLE_ST
・・・(全ステータス分用意)
StateFuncTable[FOLLOW_CMD_ST] = OnFOLLOW_CMD_ST

こんなのを作ってやると


-- 状態処理
StateFuncTable[MyState]()

分岐無しで呼び出しスッキリ。

285(○口○*)さん :06/04/03 21:10
ちなみに、テーブルに突っ込む関数は、
関数テーブルを作成する前に定義しておく必要がある。
また、分岐条件になる変数(上の例だとMyState)に想定外の値が来た場合、
呼び出すべき関数が存在しない為にエラーになるので注意。

286(○口○*)さん :06/04/03 21:17
>>284
それならコード中の
  MyState = ○○○_ST
を全て
  StateFunc = On○○○_ST
に置き換えて
  -- 状態処理
  StateFunc()

これでいいんじゃない?
StateFuncへの初期値の設定はOnIDLE_STの宣言より後にする必要があるけど。

287(○口○*)さん :06/04/03 21:21
ジェバンニが一晩でやってくれました

288(○口○*)さん :06/04/03 21:29
>>286
状態を表す数値自体はTraceとかで使えると思うんで、
関数の飛ばし先をゴリゴリ替えるよりは判りやすくなるんじゃないかな、と。

289(○口○*)さん :06/04/03 21:57
>>282
argがnに対応するのは原理的に不可能じゃないかな。

>>283
debugライブラリ使ってるようだから、少なくともそのままじゃ
使えなさそう。
でも_Gにmetatable使えるのね。

>>284-285
>関数テーブルを作成する前に定義しておく必要

StateFuncTable[IDLE_ST] = function(...) OnIDLE_ST(unpack(arg)) end

もしくは根本的に手を入れてしまう
StateFuncTable[IDLE_ST] = function(myid)
--ここでOnIDLE_ST関数を定義
end

290(○口○*)さん :06/04/03 22:27
>>289
なるほど、そんな書き方も出来るのか。
参考になった。

291(○口○*)さん :06/04/04 00:21
話の流れをぶったぎりますが・・・うちのAIを使っている方からの指摘で、
興味深い話があった&試験的に対策を打ったネタがあるので、情報として公開。

いくつかのAIで、
「他のユーザーが攻撃している敵を殴らない『横殴り防止』」と、
「上記横殴り防止の例外・共闘していいキャラを指定できる『友達登録』」とが
サポートされてますよね。
これに関して「味方のホムと共闘できない」という話が指摘されました。
味方ホムは友達登録されていないので、味方ホムの殴っている敵への攻撃は
横殴りと判断してしまい、自律攻撃をしない・・・という状況です。

ホムンクルスについても普通と同じように友達登録で対応できそうなものですが、
「プレイヤーキャラは、リログしてもIDは一意」なのに対して、
「ホムンクルスは、リログやテレポなどでIDが変わる」という話があり、
普通に登録してしまうとリスクがあります(例えば将来、まったく関係ない第三者のホムに
そのIDが割り当てられると、誤爆してしまう)。

で、ちと悩んだ結果、ホムンクルスも普通に友達登録しておいて、
だけどその「ホム友達」は、見失ったら自動的に友達登録を削除してしまう、
という手を打ってみました。
なにかの参考になれば。
ttp://tomose.dynalias.net/RO/index.php?%A5%DB%A5%E0%A5%F3%A5%AF%A5%EB%A5%B9
friend.lua 内、CheckTemporalyFriend()あたり。

# とはいえ、かなり強引な仕様なので・・・もっとスマートなアイディアは無いものですかね。
# GetV(V_OWNER, <ホム友達ID>)とかで、オーナーが引けるとラクチンなんですが。

292(○口○*)さん :06/04/04 00:27
質問っす。

特定条件を満たした値を配列で返す関数作ったのですが、
その条件に満たないものしかない場合、配列の要素が0のまま
返してしまっています。

下記みたいなことしたいんですが、無理ですか?

local array = {}

array = GetArray() ←ここで落ちる。

if array ~= nil then
...
end
------------------------------------------

こうするしかないのかな?

local array = {}

if GetArray() ~= nil then
array = GetArray()
end

すると判定のために配列作って、んでもってまたもや配列作ってと・・・
無駄なきが。。。

293(○口○*)さん :06/04/04 00:31
>>292
俺だったら番兵くんを採用するが・・・このあたりは人それぞれかなあ。

294(○口○*)さん :06/04/04 00:33
バンペイくんって何ですか?
スクルドの作ったロボット?

295(○口○*)さん :06/04/04 00:42
>>292
そもそも、書いてある部分のコードで落ちることはないと思うけどな
array = nil
はいつでもできる。
nilのまま演算してるとか、何か別の要因じゃないかと。

ちなみにこういう書き方もできるよ。
array = GetArray() or {}

GetArray()がnilかfalseの場合にはarrayが{}になる。それ以外はarray=GetArray()と一緒。

296(○口○*)さん :06/04/04 00:44
>>294
やっぱそっち方面に行ったか・・・OTL
番兵ってのはプログラム用語では「処理をうまく動かすためのダミーデータ」を表す。

↑の例で使う場合は、□=通常データ、■=番兵くん として
array={□,□,□,□,□,■}とデータを入れ、ループで配列を先頭から読み込んでいって
「■が出たら処理を止める」という判定をする。

これなら、要素0の場合は配列の最初でとまるし、要素がある場合も終端まで全部読み込める。
ちょっと手間だけど慣れれば楽だぜ。

297(○口○*)さん :06/04/04 00:46
>>295
なるほど、参考になりました。

>>296
Σ(・ω・;)
おばかでごめんなさい。
わかりやすい解説をありがとうです。

298(○口○*)さん :06/04/04 00:46
>>292
array = GetArray() or {}

仮引数のデフォルト値とかで使える技なので覚えておくといいよ。
function f(x)
 local x = x or 1
return x + 1
end

299(○口○*)さん :06/04/04 00:48
このスレならリロードいらないと思ったのに…orz

300292=294 :06/04/04 01:02
すいません、>>295さんの方法も>>296さんの方法もためしたのですが
結果がほぼ同じ・・・。
GetArray()に問題ありそうなのですが、よくわからないので具体的に質問させてもらいやす。
VBならこんなことで悩まないのに・・・しくしく。

ようは、GetEnemysA類をカプセル化しようとしてるんですが、GetEnemysA内の最初のループのみを
GetActorsとして関数化し、敵対象として認識可能なオブジェクト配列を返すようにします。
で、次にGetEnemysA内の次のループでやってる最短距離にいるオブジェクトの抽出を
GetNearTargetとして関数をつくり、こいつの引数にGetActorsで作った配列を渡します。
で、結果として得られるresultを返す。というものなのですが・・・。

ソース全晒ししたほうがよいですか?

301(○口○*)さん :06/04/04 01:11
その前に何のエラーで落ちるのか書いてみたら?

302(○口○*)さん :06/04/04 01:11
>array = GetArray() ←ここで落ちる。
GetArray == nilか、もしくはGetArray()定義でミスしてそう。

エラーメッセージ、GetArray()の定義、それを呼び出す部分
(エラー発生箇所?)を晒してもらえるとエラー追えるかも。

303(○口○*)さん :06/04/04 01:12
エラー内容もあれば答えやすいと思う。

304292=294 :06/04/04 01:16
エラー内容はnilエラーです。

attempt to call global 'GetActors' (a nil value)

というエラーなんですが、GetActorsがnil返してるから
代入できないよ。ってことじゃないんですかね?

305(○口○*)さん :06/04/04 01:18
>>304
「GetActorsがnilだからGetActors()を実行できないよ」

306292=294 :06/04/04 01:19
連投すいまそん。以下、ソースです。

呼び元
function GetMyEnemyA ()
local result = 0
local enemys = {}
--ホムンクルスを攻撃しているオブジェクトのリストを生成
enemys = CreateTargetListForHom() ←※エラー指摘行
--リストよりホムンクルスとの距離が最も近いオブジェクトを取得
result = GetNearEnemyInTargetList(enemys)
--取得したオブジェクトを返す
return result
end

307292=294 :06/04/04 01:19
function CreateTaregetListForHom()
local actors = GetActors ()
local enemys = {}
local index = 1
local target
--クライアントに送信されるオブジェクトの要素から
--ホムンクルスに攻撃を行っているオブジェクトを取得して配列に追加する。
for i,v in ipairs(actors) do
--アルケミスト自身、ホムンクルス自身は対象外とする。
if (v ~= g_OwnID and v ~= g_HomID) then
--オブジェクトの攻撃対象を取得
target = GetTarget(v)
--攻撃対象がホムンクルスであるか
if (target == g_HomID) then
--攻撃対象がホムンクルスである場合
--敵対象リストにオブジェクトを追加
enemys[index] = v
--リストインデックスをカウントアップ
index = index+1
end
end
end
--末尾に0追加(ループ終了判定用ダミー値)
enemys[index] = 0
--生成したリストを返す
return enemys
end

308(○口○*)さん :06/04/04 01:21
>>295
array = GetArray()

ふつうにnilかえってくりゃおちるな。

ってか番兵君とか知ってるほうが少数派だっていう前提で書こうよ。

309(○口○*)さん :06/04/04 01:24
>enemys = CreateTargetListForHom() ←※エラー指摘行
>function CreateTaregetListForHom()

つまり>>280…。

310292=294 :06/04/04 01:27
うわあああああああああああorz

ごめんなさい、ごめんなさい・・・。
恥ずかしい・・・。

ありがとうございました(;ω;)

311(○口○*)さん :06/04/04 01:27
これはエラー指定行から把握可能だったな…

312(○口○*)さん :06/04/04 01:27
アレだ。
怪しいときは、まずタイプチェックと、関数名そのもののこぴぺだ。
・・・俺も今日、それにはまってたさ oTL

313(○口○*)さん :06/04/04 01:30
配列の中を回して、該当なければ最後のデータってのは
わざわざループ書いてあげなきゃだめなのかいな。

件数多かったら微妙じゃないのかな?


array = {}
array.default = 0
array={1,1,2,2,1,0}

こんなんじゃだめ?

314292=294 :06/04/04 01:37
>>313
ループで配列作ってたのは、>>307のように不特定多数から
要素を生成する必要あったからなのです。

なにはともあれ、ありがとうございました。
これだからインタプリタは苦手だああああ。

315(○口○*)さん :06/04/04 09:25
タイムリーに罠にはまってたわけねw
とりあえずインタプリタとの関連性に疑問視。
打ち間違えは関係ないやんw
どっちにしてもコンパイラに同じこといわれる。
この場合はLuaのお手軽仕様に文句言うべきかと。

でも、たしかにネトゲみたいに仮想世界をデータ上に作ってる場合が
一番OOPの力を発揮するんだけどね・・・

316292=294 :06/04/04 09:55
>>315

たしかに・・・。インタプリタ関係ないっすね;
SDKでの開発になれてるから、エディタのみだとミスが目立ってしまいまふ。

で、やりたいことが未だ実現できておりませぬ。
どなたか愛の手を・・・orz

317292=294 :06/04/04 10:10
>>307の関数で配列を返していて、生成過程のループでは
しっかりと要素の中身を書き込んでいるようなのですが、
>>306の呼び元で受け取ってその後の
GetNearEnemyInTargetList(enemys)
内の処理がうまくいきません。

ちなみに引数を配列という指定にする場合
function AAA(array{}) end
みたいにしないと駄目なんですかね?

なぜか受け取った変数の中身はnilが参照されておりまふ・・・。

318(○口○*)さん :06/04/04 10:16
↓こんな感じにしておけば、壁進入不可とかのチェック
もできるんじゃね?と思ったが、どうかな?
エラーや動作チェックはしてない。

if(memoX,memoY==GetV(V_POSITION,MyID)) then --●同じ位置であるか確認
sel=0 --●元に戻して
return --●抜ける

else --●同じ位置でないならば
sel=sel+1--●同じ位置でない場合、進む距離を減らす
end
memoX=x,memoY=y+5 --●移動先を記憶
Move(MyID,x,y+5-sel)

319(○口○*)さん :06/04/04 10:30
>>317
>function AAA(array{}) end
・・・っていう宣言は不要。普通に
function AAA( array )
・・・の宣言で、arrayに配列をいれて大丈夫。似たような関数(敵IDが並んでいる配列から
最寄&最優先の敵を探す)を作ってるから、間違いない。

本当にnilが入ってきてる?気をつけないとならないのは、
array[1]=1, array[2]=2 ・・・となっていても、array=nil ってのはあるよ。

320(○口○*)さん :06/04/04 10:59
GetNearEnemyInTargetListも晒してくれ。
たぶん
function f(x)
 local x -- nilで初期化される
end
なんてことしてると思う。
ちなみに仮引数はもともとlocal。
for文のi,vとかもforブロックローカル。

>array[1]=1, array[2]=2 ・・・となっていても、array=nil ってのはあるよ。
nilに[]でアクセスすることはどうやってもできないはず。

321(○口○*)さん :06/04/04 11:28
>>318
どこに組み込むのかわからないからコメントしにくいけど、
memoX,memoYが更新される前に現在位置との一致チェックが入るようだから
まったく動かなくなると思う。
あと「移動途中だから目的地到達してない」ケースに対応できなさそう。

322292=294 :06/04/04 13:00
すんません、寝てた・・・。

function GetNearEnemyInTargetList (enemys)
local result = 0
local min_dis = 100 --デフォルト比較距離
local dis --ホムンクルスと敵対象の距離
--追加された敵対象リストより、ホムンクルスとの距離を比較し
--ホムンクルスとの距離が最短であるオブジェクトを敵対象として
--オブジェクトのIDを返す
for i,v in ipairs(enemys) do
--ホムンクルスと敵対象の距離を取得
dis = GetDistance2(myid,v) ←vがnilなのでここで落ちる
--距離判定
if (dis < min_dis) then
--比較距離よりも短い場合
--ホムンクルスの敵対象を設定
result = v
--このオブジェクトとの距離を次回からの比較に使用する
min_dis = dis
end
end
--最終的に設定されたオブジェクトを返す
return result
end

323292=294 :06/04/04 13:03
あ、myidはグローバルです。
で、for i,v in ipairs(enemys) doの次で
if v ~= nil thenをかましてやるとエラーは回避しますが、
一向に処理されてこない様子。
つまりはvがnilってことですよね?
でも、そのまえのenemys作るとこではしっかり入ってるんですけど・・・。

324(○口○*)さん :06/04/04 13:05
>>322
うわー懐かしい、俺も凄い悩んだ
dis = GetDistance2(myid,v) ←vがnilなのでここで落ちる

dis = GetDistance2(MyID,v) ←myidがnilなのでここで落ちる

だったりしない?

325(○口○*)さん :06/04/04 13:05
リロードしれ俺OTZ

326(○口○*)さん :06/04/04 13:18
連投すまん
>>307で最後に入れた
--末尾に0追加(ループ終了判定用ダミー値)
enemys[index] = 0
の処理ドコでやってるんだろ

dis = GetDistance2(myid,0)
だとGetDistance2は落ちるけども。

327(○口○*)さん :06/04/04 13:22
>>322
エラーメッセージも書けw

リファレンスのipairsを見てほしいけど、vにnilが入ることは
構造上ありえないんだ。要するにnilが番兵そのもの。
(「番兵」はぐぐれば出るからかまわないと思うけど
 >>293の落ち度はそれを「番兵くん」と呼んだことじゃないかな)

for i,v in ipairs(nil) do print(i,v) end
--> bad argument #1 to `ipairs' (table expected, got nil)

for i,v in ipairs({nil}) do print("looping",i,v) end
-- 反応なし(ループしない)

for i,v in ipairs({1,nil}) do print("looping",i,v) end
--> looping 1 1

require"Util.lua"が済んでなくてGetDistance2が未定義とかはない?

328(○口○*)さん :06/04/04 13:28
何故エラーが出てるというのにエラーメッセージを書かないのか。
とりあえず、ホントに v が nil なのか TraceAI(v) してみたほうが。

329(○口○*)さん :06/04/04 13:32
うう、初期化処理じゃないから、どこでUtil.lua呼んでもだいじょうぶだ。
とりあえずエラーメッセージ見ないとなんとも。
もしほんとにGetDistance2にnil渡したなら、エラー行は
GetDistance2のGetVになるはず。

330(○口○*)さん :06/04/04 14:02
ふと思いついた。
>>283の簡易版で、値がnilなグローバル変数を読み込んだときにエラーにする方法。
setmetatable(_G, {__index = function(s,v) error(string.format([[global variable "%s" is nil value. (probably uninitialized)]], v)) end})

代入はふつうにできる(だから代入時のtypoは検出できない)けど、
呼び出したときのtypoはかなり検出しやすくなると思う。

ただし、わざとグローバル変数にnilいれるのもダメになる
(呼べなくなる)から用法・用量はお守りください。
誤ってnil代入してしまったときも、そのあとの呼び出しで
このエラー出るだろうし。

331292=294 :06/04/04 14:11
すんません、エラーMSGメモってなくてROつながらないので
内容書きませんでした。

>>329さんのご指摘どおり、エラーメッセージはGetVに渡した値がnilというような内容でした。
とりあえずデバッグ不足っぽいのでROつながったらもうちょい探ってみます。
ありがとうです。

332(○口○*)さん :06/04/04 17:40
>>330じゃエラー行表示がおかしくなりそうなので、これで。
setmetatable(_G, {__index = function(s,v)
 error(string.format([[global variable "%s" is nil value. (probably uninitialized)]], v),2)
end})

333(○口○*)さん :06/04/04 17:47
>>284
うちは
proc = {
 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
}

AIの中で
 -- 状態処理
 proc[MyState+1] ()
これでとりあえず動いてるからさわってないけど怖いなあ

334(○口○*)さん :06/04/04 20:35
すいません、初心者質問かも知れませんが
MOB、スキルのID取得方法など教えてもらえないでしょうか。
GetVで取得するものだとは思いますがそれ以降がどこを読んでも頭に浮かびません。
とりあえず今考えているのは

状態偏移後GetVで数値取得
fp = io.open("FILE.txt", "w")で数値を書き込むファイルを開き
fp:write( string.format("hoge"))でどうにかして値を書き込む。
fp:close()で閉じる

これを取得したいIDに関係する状態の場所に追加すれば良いのではと考えているのですが
肝心のGetV以降がどうすればいいのか分かりません。
どうかよろしくお願いします。

335(*○口○)さん :06/04/04 21:05
function IdSave (id)
  local GX, GY = GetV (V_POSITION,id)
  fp = io.open("AI/USER_AI/FILE.txt", "a") -- USER_AIフォルダを指定すること!("a"は追加書き込み)
  fp:write( string.format("check date\t%s\n", os.date("%Y/%m/%d %H:%M:%S")) ) -- 記録時刻
  fp:write( string.format("[ %s, %s ]\t%s\t=\t%s\n", GX, GY, id, GetV(V_HOMUNTYPE,id)) ) -- idの座標、id、idのHOMUNTYPE
  fp:write("\n")
  fp:close()
end

Attack (MyID,MyEnemy)前後にIdSave (MyEnemy) -- MOBIDげちゅ
OnSKILL_OBJECT_CMDとかにIdSave (MySkill) -- スキルIDげちゅ

336(○口○*)さん :06/04/04 21:26
追跡ルーチン参考
ブレゼンハムアルゴリズム
/2は*0.5に置換えした方が良い

ttp://javagame.main.jp/ai/los.html

337334 :06/04/04 22:52
>>335
functionで書いてくれるとはさすが住人だぜ!
ありがとう!

338(○口○*)さん :06/04/04 23:32
traceaiじゃだめなのか・・?

339(*○口○)さん :06/04/05 09:49
traceaiの方がいいかもしれんが余計なTraceAI ()消す手間考えたら
>>334には>>335がいい

340(○口○*)さん :06/04/05 12:43
前にここに張られてた、レベル指定トレース導入したら楽だよ
ピンポイントで出したいものだけだせるし、全部だすこともできるし。

341140 :06/04/05 13:07
スキルを遠距離攻撃してくるやにを撃ちつつ
自分の近くの敵に通常攻撃をさせたりとか
いろんな種類を組み合わせたくて作ったんだけど
Luaの配列処理って重たいのかな?
---------------------------------------------------------------------
--主人を遠距離攻撃中の中から一番近い敵を探す
function GetOwnerOutRangeEnemy()
 local actors = {}
 local resultEnemyID = 0
 
 actors = GetActors()--画面内の全員
 actors = SelectActors(SELECT_ENEMYS, actors)--↑のうち攻撃可能
 actors = SelectActors(SELECT_OWNER_TARGET, ators)--↑のうちターゲットが主人
 actors = SelectActors(SELECT_OUT_RANGE, actors, GetV(V_OWNER,MyID), 3)--↑のうちオーナーから3セル以上離れてる
 resultEnemyID = GetNearActorID(MyID, actors)--↑のうち自分に一番近い
 return resultEnemyID
end
---------------------------------------------------------------------
SelectActorsがインターフェースになっててelseif連打してて
SELECT_〜の定数ごとに↓の様なのに引数調節して関数群から呼んでる
---------------------------------------------------------------------
--範囲外の相手を返す
function GetOutRangeActors(argActors, argID, argRange)
 local resultActors = {}
 local resultActorsIndex = 0

 for argActorsIndex, actorID in ipairs(argActors) do
  if GetDictance2(actorID, argID) >= argRange then
   resultActorsIndex = resultActorsIndex + 1
   resultActors[resultActorsIndex] = actorID
  end
 end
 return resultActors
end
---------------------------------------------------------------------
1回のタゲ判定でこの処理が5〜20回程度走ることになるんだけど
環境によってはさすがに重くなりすぎるかな?
まだ、自分のにすら組み込んでないから動くかどうかすら謎だけど
質問するほうも回答するほうも提案するほうもタブとか面倒だから
テンプレに入れれるようなうpろだどこかに無いかな?テキストだけでいいし

342140 :06/04/05 13:30
わかりにくいな・・・
要点はこの処理重すぎてまともに動かなかったりする?ってこと
デフォAIのGetMyEnemyAを1判定につき10回ずつぶん回すと思えばいい

自分で試せないのはまだ商人だから・・・
おうちに帰りたいよママン

普通にループにif埋め込めばいい話ではあるけど
SelectActorsの組み合わせで細かい条件を簡単に定義できる
だからいろんな特殊条件のGet〜を大量に作るときに楽に書けて
条件がわかりやすくなる。定数部分だけ見ればいいからね。

あと利点にこれで作ったリストごとに優先順位をつけてから
その中で優先度が高いものの順に調べていったり

後はROの仕様変更あっても内部実装の条件変えればメインに手を加えなくてもいい
何十個もばらばらに条件作ってたら全部のif書き換えるだけでグロッキーになる

うpろだあれば作った分だけ全部まとめて上げるんだけど
今のところ実装した定数はこんなとこ
SELECT_TARGET --ID指定タゲで分類
SELECT_MY_TARGET --自分タゲで分類
SELECT_OWNER_TARGET --主人タゲで分類
SELECT_FREE_TARGET --未タゲで分類
SELECT_MOTION --指定モーションで分類
SELECT_ENEMYS --IsMonster()で分類
SELECT_IN_RANGE --指定範囲内で分類
SELECT_OUT_RANGE --指定範囲外で分類

343(○口○*)さん :06/04/05 13:52
スペルミスが・・・って突っ込みは置いといて、

function IsOwnerOutRangeEnemy(id)
  if not SELECT_ENEMYS then return false end
  if not SELECT_OWNER_TARGET then return false end
  if not SELECT_OUT_RANGE then return false end
  return true
end

こんな風なのを for の中に入れてもいいんじゃないか?

344(○口○*)さん :06/04/05 13:54
>>341,342
ポイントになるのは「配列をなんども関数の引数・戻り値に使ってるから、コピーコンストラクタ走りまくりで遅いんじゃ?」って話ですよね。
こればっかりは試してみないとわからないんじゃないかな。
環境(ROクライアント&PCそのもの)のメモリー管理状況にも依存しそうな気はするし。

実装論理的に面白そうなのは確かなので、興味はある。
ただまあ、やっぱり実際に自分で動作を確認してから公開するのがいいんじゃないかと。

345(*○口○)さん :06/04/05 14:04
>>341,342
function GetOwnerOutRangeEnemy(owner_dis)
  local result = 0
  local actors = GetActors ()
  local enemys = {}
  local index = 1
  local myowner = GetV (V_OWNER, MyID)
  for i,v in ipairs(actors) do
    if (v ~= myowner and v ~= MyID and IsMonster(v) == 1) then -- ケミかホム自身でない攻撃可能対象だったら
      if (GetV (V_TARGET,v) == myowner) then -- タゲがケミだったら
        if (owner_dis < GetDistance2 (myowner,v)) then -- ケミから指定距離owner_dis以上離れていれば
          if (GetV(V_MOTION,v) ~= MOTION_DEAD) then -- 敵が死にモーションでなければ
            enemys[index] = v -- 敵のリストに追加
            index = index+1 -- インデックスを1増やす
          end
        end
      end
    end
  end
  local min_dis = 15
  local dis
  for i,v in ipairs(enemys) do
    dis = GetDistance2 (MyID,v) -- ホムと敵との距離を取得
    if (dis < min_dis) then -- 最小距離より近ければ
      result = v -- その敵をターゲットとする
      min_dis = dis -- その敵との距離を最小距離とする
    end
  end
  return result
end

これ位で十分じゃないか?
わかりにくいと思ったら「わかりやすく」、処理の重さが気になるのなら「処理を簡素に」
汎用性や追加条件、簡可変性を考える前にまず動く物を作った方がいい

とか動作検証もせずに言ってみる(ぇ

346(*○口○)さん :06/04/05 14:19
local min_dis = 15 -- 15の数字は適当だったからデフォの100でいいかも

失礼>>140見てなかった
が、リストを返す関数よりIsMonster(id)見たいにidが条件に当てはまるかどうかを
1or0とかで返す関数の方がスマート&ライトでいいと思う
何よりどう頑張ったってif文から逃げられんのだからトコトン使いまくる方が好き(限度は大切

347(○口○*)さん :06/04/05 14:20
>>345
というか、必要十分の話ではないだろ?

348140 :06/04/05 14:56
>>344
そうそう、そういうこと
翻訳ありがとうorz
後はfor argActorsIndex, actorID in ipairs(argActors) do
これとかもちょっと気になってるところ
本来1回だったのを何回もまわすからテラオオスなMHとかちょっとやばそうだなぁと

>>345
うん、やろうとしてるのはその通り、それぞれif処理が分かれてるだけ
というかもともとデフォAIからいじってるからほぼ同じもの書いてたんだよね。
そういう関数を10個も20個も並べて書くと見にくさ爆発だから先に外堀埋めておこうかと思ったわけ
どうせホム呼べるようになったらメインの動きいじったりホムLv上げに夢中になってしまうのは目に見えてるからw

でもまぁ、実際動かしてみてどうなるかとしか言いようは無いのは事実だね
きちんと管理してくれてぜんぜん余裕かもしれないし
南十字路でテロなんて起きようものなら1フレーム10秒とかになるかもしれないし
こればっかりはシミュレーターでは計りようが無いからなぁ
あと少しだしがんばって商人育てることにするよ

349140 :06/04/05 15:02
リロードは大切!orz
仕事中の息抜きのはずがちょっとテンパリすぎてるので今日はこれでw

こういう条件もってな追加があれば動かせるかどうかは別として受け付けとくよ

350(○口○*)さん :06/04/05 15:19
可変長配列にして第一引数をactors、定数指定をそれ以降にまわしてGetSelect を一回にしたらどうだろ

351(○口○*)さん :06/04/05 16:09
actors[]を最初に1周させて
各条件の評価結果をプロパティ追加して埋め込んでおくとか

352(*○口○)さん :06/04/05 16:54
--------------------------------------------------
CheckST(C_ENEMY, id) -- idが攻撃可能かどうか(IsMonster()のみ)
CheckST(C_MONSTER, id) -- idが敵モンスターかどうか(IsMonster()の内プレイヤーとプラントmob以外)
CheckST(C_TARGET, id1, id2) -- id1のタゲがid2かどうか(未タゲはid2を0に)
CheckST(C_MOTION, id, MOTION_**) -- idのモーションがMOTION_**かどうか
CheckST(C_IN_RANGE, id1, id2, range) -- id1がid2からrange以内かどうか
CheckST(C_OUT_RANGE, id1, id2, range) -- id1がid2からrange外かどうか
--------------------------------------------------
定数
C_ENEMY = 0
C_MONSTER = 1
C_TARGET = 2
C_MOTION = 3
C_IN_RANGE = 4
C_OUT_RANGE = 5
--------------------------------------------------
elseif連打のインターフェース
function CheckST(status)
if (status[1] == C_ENEMY) then CheckEnemy(status[2])
-- 略 --
end
end
--------------------------------------------------
関数群
--------------------------------------------------
function CheckEnemy(id)
if (IsMonster(id)==1) then return true end
return false
end
-- 中略 --
function CheckInRange(id1,id2,range)
if (GetDistance2(id1,id2) < range) then return true end
return false
end

function CheckOutRange(id1,id2,range)
if (GetDistance2(id1,id2) > range) then return true end
return false
end
〜続く〜

353(*○口○)さん :06/04/05 16:55
〜続き〜
function GetOwnerOutRangeEnemy(owner_dis)
  local result = 0
  local actors = GetActors ()
  local enemys = {}

  local index = 1
  local myowner = GetV (V_OWNER, MyID)
  for i,v in ipairs(actors) do
    if CheckST(C_MONSTER, v) then -- idが敵モンスターかどうか
      if CheckST(C_TARGET, v, myowner) then -- vのタゲがmyownerかどうか
        if CheckST(C_OUT_RANGE, v, myowner, 3) then -- vがmyownerから3セル以上離れてるかどうか
          enemys[index] = v
          index = index+1
        end
      end
    end
  end
  return GetNearActorID(MyID, enemys) -- enemysのうち自分に一番近い
end

最後のGetNearActorID()はリストから選ぶからそのまま使ってる
こうすれば>>341と同じように特殊条件のGet〜を作る時もCheckST()の組み合わせで作れて
forループもGetActors()からの選り分けと一番近い敵の選び出しの2回だけで済む

って事が言いたかったんだけど、要は>>341,342が処理遅いかどうかって質問だったのに書いてから気づいたって事orz

>>341の状態でも戦闘時にのみ呼ばれるならそこまで遅くないと思う
町に居る時は戦闘モードにならない様に組めばいいだけ
さらにSelectActorsの順番を「ターゲットが主人>攻撃可能>3セル以上離れてる」
とか選別条件を大まか>細かくにすればさほど重くならず動けると思うよ

354(○口○*)さん :06/04/05 17:09
>>341
一回の処理(一度のAI()呼び出し)内ではクラから得られる
情報が変わらないんじゃないかと思う。(未検証、違ってたらごめん)
だから何度も呼ぶことがわかってるなら
 actors = GetActors()--画面内の全員
 actors = SelectActors(SELECT_ENEMYS, actors)--↑のうち攻撃可能
 actors = SelectActors(SELECT_OWNER_TARGET, ators)--↑のうちターゲットが主人
このへんは利用頻度高そうな上に結果が変わるものじゃないから
キャッシュしておいていいかも。

もっとも負荷なんて、やってみて重いと思ったら対策すればいいよ。
理論的に考えるのはもちろん大事だけれども、ボトルネックを
きちんと見極めることがもっと大事。
まだ環境がないなら、そういう実装的な部分は後回しにして
アルゴリズムを考えていればいいんじゃないかなぁ。

あぷろだはMMOBBSのでいいと思うけど、plain/textダメだっけ?

>>344
テーブルは参照渡しだよ。

355344 :06/04/05 17:48
>>354
>テーブルは参照渡しだよ。
あ、そうなんですか。そこまではLUA仕様読んでないわ・・・情報さんくす。
#つーか、ほんとに言語に詳しくない人置いてけぼりだな(^^;

まあ正直に言って、わたしはそのあたりはとりあえずOS(ROクライアント)任せでやってて、
負荷なんざまるっきり考えてないコード書いとります(^^;;
仕事や本格的なアプリを作るとかならともかく、そこまでシビアな要求もない遊びで使うコードに
そこまで労力かけたくないわ(笑)

356(○口○*)さん :06/04/05 18:14
逆に漏れは、自分用だからどうでもいいぐらいに最適化とか試してるな。
AIの半分はタゲ選別用になってるぜ!

357(○口○*)さん :06/04/05 18:54
>354
>一回の処理(一度のAI()呼び出し)内ではクラから得られる
>情報が変わらないんじゃないかと思う。(未検証、違ってたらごめん)

V_MOTION は変わってた。
そのせいもあってポルセリオの死体(DEADとSTANDの交互表示)粘着が
確率でしか抜けられん_| ̄|○

358(○口○*)さん :06/04/06 00:26
luaでエラーこくと、メッセージボックス出まくって操作出来なくなる
糞仕様はどうにかならんもんか。

359(○口○*)さん :06/04/06 00:47
それで固まってて必死に修正してなんとかエラー閉じてたら
何か会話ログのこっててよく読んだらBOT扱いされてた。
たぶん本体動かないくせにホムだけ動いてたからだろうな…。

360(○口○*)さん :06/04/06 00:56
>>358
とりあえずエラー直してからOK押せばそのまま正常にロードしなおすよ

361(○口○*)さん :06/04/06 01:03
>>358
ウィンドウモードでROクライアントを動かしている俺は、
エラーでたらファイルと行番号メモって即ROクライアント殺してる。
(右上の×クリックして)

最初のころは360氏紹介のやりかたで直してたんだけど、狩場でそれやって、
エラー修整してる間にアクティブ敵に叩きつぶされたことが(笑)
なので、これは街中限定でお勧めする。

362(○口○*)さん :06/04/06 01:19
以前の AI.lua を AI_MAIN.lua に名前変更し、AI() を AI_MAIN() に変更。
AI.lua を以下の内容のみにする。
function try(func, ...)
local ok,err = pcall(func, unpack(arg))
if (not ok) then
TraceAI(err)
AI = function() end
end
end

function AI(id)
try(AI_MAIN, id)
end
try(function()
require 'AI_MAIN.lua'
end)

これで、エラーは TraceAI.txt に出力されて同時にホムは停止。
メッセージボックスは出なくなる。

363(○口○*)さん :06/04/06 02:19
>>362
便利そうだ

364(○口○*)さん :06/04/06 09:45
似たようなのは作ったけれども、やっぱファイル名変えないと
構文エラーは防げないよね…。

こうすればファイル名変更だけで済むはず。
function try(func, ...)
 local ok,err = pcall(func, unpack(arg))
 if (not ok) then
  TraceAI(err)
  AI = function() end
 end
end

try(function()
 require 'AI_MAIN.lua'
end)

do
 local _ai = AI
 function AI(id)
  try(_ai, id)
 end
end

365140 :06/04/06 15:06
>>353
なるほどターゲット分類を最初にもってくれば
それ以降のループは大幅に減らせますね
街中とかも主人やホムタゲるPCなんて片手も居ないからそのままで問題なさそう

>>354
ということは引数渡しのオーバーヘッドは気にするほど無いと考えられるのかな
あとキャッシュは採用したい案だけど要調節って感じだなぁ
とりあえずはホムタゲ、主人タゲの敵あたりかな

やっと転職あとはスキル覚えて呼び出すだけ
週末には組み込んで実験できそう

366(○口○*)さん :06/04/06 16:26
>>365
転職おめ
そしてAI弄りすぎで狩りの少ない生活へようこそ

367(○口○*)さん :06/04/06 18:35
>>357
な、なんだってーorz

・一度のAI呼び出し中に変わらないと「見なす」
・ただしモーションは不安定だからキャッシュやめとけ
これでどうだろう。

>>366
AIいじり・ホムLv上げ・PT公平狩り
どれも独立なのが辛い…。
弊害考えるとやむを得ないとはいえ、せめてホムLv上げと
PT公平狩りが両立できればなぁ。

368(○口○*)さん :06/04/06 18:43
ホムの分は主人にしか入らない?

369(○口○*)さん :06/04/06 19:03
>>357
死亡確認したいなら、敵の現在座標見るって手もあるぞ。
死んでると-1返ってきたはず。

370(○口○*)さん :06/04/06 19:54
>103-104
なおかつポルセリオの死体はDEADとSTANDの交互表示だった。

IDを記憶しておくのは即沸きに対応できない可能性があるので
現状は判定には使っていない。
死体IDが通常IDとかぶらないのさえ確認できれば
(1戦闘の単位時間で消滅していることを期待して)
死体IDを次のタゲ決まるまでキープするだけでいいんだがなぁ。
試しに組み込んでみるか。

371(○口○*)さん :06/04/06 20:04
>>364
なるほど
ついでに、require の直後に do end の中身いれたらいいかも

372(*○口○)さん :06/04/06 20:06
>>369
雑談・要望スレで出てた事だけど、mobが死亡すると同じ座標に
別IDの死亡モーション専用のオブジェクトが発生するらしい。
で、>>357のはその専用のオブジェクトがDEADとSTAND交互ってことかと
専用にしろ目の前に存在しているオブジェクトだから-1でなくちゃんとした座標が返ってくるはず

・ATTACK、CHASEでMOTION_DEADならIDLE
・Get**Enemy系でMOTION_DEADでない事をチェック
が今の所、間違いが無い対処

向こうで「通常のmobと異なる専用のオブジェクトのid範囲で除外」
って案があったが全てのmobに対応できるか等、不確定要素が多く
まだ対処のサンプルコードは示されて居なかったと思う

373(*○口○)さん :06/04/06 20:09
雑談・要望スレじゃないココだorz

374(○口○*)さん :06/04/07 09:18
死体が別オブジェクトだというなら
そもそもIsMonsterが通る時点でOS(クライアント)のバグだよね
敵のターゲット情報更新タイミングの調整と
移動不可セルの視認関数がほしいところ
もしくは射線が通っているかの判定を流用したものだけでもいい

追加要望を受け付けると公式のスクリプトマニュアルにハッキリ書いてあるしやってもらわないとねw
>RO開発室ではスクリプトを直接編集しなくてもゲームを楽しめるよう、
>良いスクリプトを提供する予定です。
>プログラミングに慣れない使用者に対しても自分の目的に合う人工知能を
>実現するのに役に立つように修正、補っていく予定です。
こっちの二つはユーザー側で情報共有すれば何とでもできるけど

>プログラミングに興味がある使用者のためにも持続的に機能を追加する予定です。
こっちは開発側で無ければできない

375(○口○*)さん :06/04/07 10:40
>374
移動可否チェックは、俺もほしい。
現状のクライアントでも「マウスを動かしても地面にカーソルがでない」動作、
つまりクライアント上で「進入不能セルは判る」ので、これをAIレベルで取れるだけで
だいぶ違ってくる。
目標地点までの経路判定して、進入不能なら移動目標を変える、とかできるので。

あとでWebヘルプデスクに書きにいってくるわ。

376(○口○*)さん :06/04/07 10:44
>>372
あぁ、「死亡確認ができない」じゃなくて、
「倒した後の索敵でひっかる」ってことか。

ノンアクティブ後回し設定だから、全然気にしてなかったな・・・。
死体オブジェ特有の状態探してみるか。

377(○口○*)さん :06/04/07 10:46
追加して欲しい機能って何だろうね

任意のエモを出せると、状態変移を目視確認できるし是非欲しいね

他には将来的に親密度に関係したスキルが追加される予定だし
親密度の取得は可能にして欲しい所
一緒に満腹度取得も出来ると空腹アピールが出来て良いんだけどねぇ

もちろん、移動可否チェックもホムの機能向上の上で是非実装してほしい

378(○口○*)さん :06/04/07 11:00
満腹度が取得できちゃうと自動安息が強化されて放置プレイが増えるから
ケミ全体の評価が下がってよくないかもしれない。

エモは何故ないのか疑問だよな・・・。ショックエモ連発してぇ。

379(○口○*)さん :06/04/07 11:29
>>378
それは、なんか本末転倒のような気がする。
満腹度取得→おなかが減った→「ご主人様、ご飯ください」意思表示できる
・・・ってのは、人工知能としては正しいはず。

どっちかというとAIから「ケミのスキルである安息が使える」ことや、
「OS(ROクライアント)を殺せる」ことが問題なのではないか。
どっちも「ホム」ではなく「ケミ」や「クライアントそのもの」を操作しているので、
ホムのAIから操作できることとしては権限過剰だと思う。


エモは出したいねぇ・・・言葉での発言は、それこそ「ぶーん」的な騒音問題を産みそうだけど、
エモくらいならやらせてくれてもいいように思うよ。

380(○口○*)さん :06/04/07 11:32
下手な実装の仕方すると
本来は
EMOTION_SHOCK = "ショック"--発言できないように"/"は自動付与
Emotion(EMOTION_SHOCK)
見たいなやり方でも
if GetV (V_MOTION,OwnerID) == MOTION_SIT then--ケミが座っていたら
 Emotion ("sit")--スキル使うから立てやゴルァ(/sitで立ったり座ったり)
 SkillObject (...
とかケミAIが強化されそうだし

ホム専用コマンド作ったり
エモ関数は完全に分離して自由にできないようにすると
エモ追加のたびにどんどん肥大化してくし
クラへの実装やらめんどくさくてやらなさそうw

381(○口○*)さん :06/04/07 11:59
普通に数値分岐にするべ。
文字コードもあやふやなスクリプトで、日本語解釈入れるなんてバグの元だし。

ポルセリオ死亡チェックしてるけど、今のところDEADとSTAND交互に出ることはないな。
一度DEADになったら、消えるまでそのままだ。
しかし、-1のIDが混ざってくるのは何でなんだろう?

382(○口○*)さん :06/04/07 12:11
そして今更気付いたんだけど・・・
死亡前IDと死体ID足すと100,000になるのな。

正確なID幅取れれば、これで死体かどうかの判定は出来そうな予感。

383(○口○*)さん :06/04/07 13:31
>>381
>エモ関数は完全に分離して自由にできないようにすると
>エモ追加のたびにどんどん肥大化してくし
>クラへの実装やらめんどくさくてやらなさそうw
ここがそれと同じこと言ってるつもりだったんだけどね

ぱっと見出てくる要望だと
移動不可の判別用
死体判別用
ホムからのフィードバック用(むしろ愛玩用?w)

後これに追加でクラからAIへのコマンドを増やしてほしい

現状送れるコマンドは5つ
Alt+T
Alt+右クリック(地面のみ)
Alt+Shift+右クリック
Alt+右クリックx2(攻撃可能対象のみ)
指定スキル使用(鳥、梅ゼリー限定)

()がいっぱいついててわかるようにどれもいまいち汎用性にかけて命令として使いにくい
唯一移動だけが相対セル位置でコマンドとして分岐できてるけど
本来は攻撃対象1クリックで出てくるはずのHOLDとか未実装なのか
立ち消えなのかわからないけどそういうものも多い

個人的優先順位
1.移動不可判別用
2.フィードバック用
3.未実装コマンド
4.死体判別(別な方法で出来そうなのでまだ最下位)

384(○口○*)さん :06/04/07 13:43
個人的にはホムのアタック判別が最優先だなぁ。
モーションでもHIT/MISS判定でも、攻撃してるのかが分かればいい。

385(○口○*)さん :06/04/07 16:25
無くて初めてわかる有難さ

Plzzzzzzzzzzzzz!
Option Expricit

にるぽ出すぎ

386(○口○*)さん :06/04/07 17:07
>>385
×Expricit
○Explicit

にるぽ出すぎな理由はわかった

387(○口○*)さん :06/04/07 19:01
オブジェクト指定でないスキルもコマンド送ってきて欲しい。
しかし、これを可能にするとAI.luaにそのスキルの処理も書き加えなきゃ動かなくなるので最初からやっててほしかった。
あとは正確なIsInAttackSightが欲しいな。
壁や崖越しでも攻撃しようとするから動かなくなる。

388(○口○*)さん :06/04/07 22:10
いちおう、Luaでも use strict に近いことは実現できるんだけどね
ROのLuaでは使えないだけで

389(○口○*)さん :06/04/07 22:41
Map = {0,0,0,0,0}

↑こんな感じに、行く狩場のマップ座標を配列に入れて、
[0だったら進める][1だったら進めない]とかって可能?
調べるの面倒そうだし、重くなりそうだが。

390(○口○*)さん :06/04/07 22:43
>>389
できるけどBOTっぽく(ry

391(○口○*)さん :06/04/07 22:44
現在居るMap名が取得出来ないからねぇ
Mob種類&MobIDから自動判別とかも出来なくないだろうけど

392(○口○*)さん :06/04/07 22:50
>>389
似たようなことかんがえて、学習用の「移動しながら入ったセルを進入可能」とログ取るものは作った。
が、「入れるセル」は調べられても、「入れない」セルを見つけることが困難。
1歩ずつ歩けば判断できるんだけど、そーすると日常的な移動が鈍くなってストレスが。

391氏指摘の「マップ判断」できない点も結構ネック。

俺は素直に、ガンホーに「進入可能セルチェック」のAPI拡張を依頼するよ。

393(○口○*)さん :06/04/07 23:29
マップデータ全部用意してユーザがそのマップにあったのを指定して読み込ませれば可能だけど
データ作る手間とマップ毎にいちいち変更する手間も相当なもんだなあ

394(○口○*)さん :06/04/08 00:46
ALT+右クリックのホムンクルス移動コマンドで、
1:地面を指定する
2:ホムンクルスがその地面に移動できたら
3:その地面をテキストにコピー(移動できないセルは、手動で)
4:適当にセルをクリックしたら、あとでまとめて配列化(0:進む、1:進めない)
5:あとで移動するときに、4でまとめた配列を読み取って
6:ホムの位置から移動先の間の配列を調べて、移動

こんな感じの考えてみたけど、できるかな?
作るの面倒なので妄想だけだg

395(○口○*)さん :06/04/08 00:58
最近気付いたんだけど
デフォルトAIにあるMoveToOwner (MyID)って
途中に障害物あってもそれを判別して避けて主人のセルまで戻ってきてるように感じるんだが
未発表なだけで実はなにかのコマンドで障害物判別できるんじゃないか?

気のせいだったらスマン

396(○口○*)さん :06/04/08 01:13
>>395
Move()を受けた後のクライアントの処理が、キャラと同じ扱いなんだと思う。
だからAIの所行ではなさげ。要はクライアントの持ってる情報を参照させろやスプリクト言(゚д゚)ゴルァ

クライアントが出し惜しみする情報を必至に探すケミ達と言うことなのだろう。

397(*○口○)さん :06/04/08 01:15
1.ダンジョン、フィールド合わせて200MAP以上ある
2.座標範囲が最大400*400程度ありファイル容量にして約350kBになる
3.クリックした点への移動チェックアルゴリズムがかなり複雑

ファイル容量はちょぃ手を加えれば1/4位には出来るんで試しに1MAP作成はしてる
正直3が一番鬼門直線上に進入不可マスがあっても通常のMoveなら
多少迂回してくれるからそれを再現できる判定方法を考えにゃならん

>>395
通常のMoveでも柱の向こう側とかクリックしても避けて移動できるから
多分クライアントの移動処理その物の障害物回避があるだけかと

398(○口○*)さん :06/04/08 01:28
>>394
前に似たようなことを考えて、実際にアプローチしかけたことがある。
ROの広大なマップの全セルをいちいちクリックしていくってのは現実的ではなさそうに思えたので、
通常の移動/追従/戦闘でのCHASE、どんな移動でも「移動したセル全てで入れたか否か」
「入れなかった最後の1歩はどこ?」・・・って感じで自動的に判断できるように、
その下準備になるものを、作った。
どんな長距離の移動も「1歩ずつ」に分解して「どこが入れるセルか」までは
調べられるような Move()のラッパーを作って。
だけど、重すぎてストレスになったので、あきらめた。

興味があるようなら、当方のAIに一部残骸があるので、参照のこと。
ttp://tomose.dynalias.net/RO/index.php?plugin=attach&pcmd=open&file=Glenelg_027.lzh&refer=%A5%DB%A5%E0%A5%F3%A5%AF%A5%EB%A5%B9

上記内、USER_AI/lib/Movelib.lua にある MoveEx2()。

399(○口○*)さん :06/04/08 01:30
>>395
こんなコードを書いて定義されてるものを列挙してみた。

function AI(id)
  for k, v in pairs(_G) do
    TraceAI(k .. "\t" .. tostring(v))
  end
  AI = function() end
end

base、string、os、io、math、coroutineの各ライブラリと
AIマニュアルに載っている関数群、
そしてTrace(注:TraceAIではない)という謎の関数が見つかった。
それっぽい隠し関数はないっぽい。

Traceがどういう関数なのかは気になるけれど…。

400398 :06/04/08 01:37
補足。
397氏の言っている「Move()が多少の迂回運動をする」という点については、
上記398で紹介したMoveEx2()では対応していない。
まさに397氏の指摘の通り、避けるアルゴを考えなければならんので。

・・・つーか、あの「ストレス無く滑るように進入不可セルを避ける」動きがある時点で、
ROクライアント上では「進入不可セルが事前にわかる」としか思えんよな(^^;;
現状のAIで使えるMove()では、どうしても「入れない」判断をするのに時間がかかるので、
あそこまで滑らかに「避ける」のは難しそう。

401(○口○*)さん :06/04/08 01:40
>>399
前スレのどっかで書いたけど、スルーされたのはナイショだ。
…書き方が悪かったとも言う。orz

402(○口○*)さん :06/04/08 02:27
その大昔、壁の向こう側でも魔法と落とせた時代
画面範囲よりもはるかに長い壁でも単純な構造ならよけて歩いた
入り組んだ複雑な構造でも画面範囲程度ならよけて歩いた

いつからかそこに制限が掛かった
それが今の中途半端なよける動作
タダの90度曲がり道でも引っかかってしまうような・・・

403(○口○*)さん :06/04/08 02:27
>>382
>死亡前IDと死体ID足すと100,000になるのな。
これって(死亡前ID + 死体ID) == 100000になるって意味?
それなら(100000-ターゲットID)が画面内にあるかどうかでターゲットの死亡確認できる?

404(○口○*)さん :06/04/08 02:36
>>401
レベル指定トレースの要望出したのあたいなんで気付いてたけど、

traceって関数がある→じゃあ別の関数名で自家製トレース関数つくりゃいいや

程度にしか気にしてなかった。むしろそういう(名前被ってるよっていう)
忠告として「traceってあるな」って言ってるのかと思ってた。

405(○口○*)さん :06/04/08 02:38
いや、ってかさ。ケミのルート取りさえ気をつけてれば、進入不可セルがどうのって
まったく必要ないんじゃないの?

万が一スタックしても、安息とか待機戻しとかでさくっと抜けられるんだし。

406(○口○*)さん :06/04/08 02:39
>>402
誤クリで延々と歩くのも問題だけど、今のクライアントの引っかかり方はほんと気になるな。
スレ違いすまん。

407(○口○*)さん :06/04/08 02:39
障害物の向こうを攻撃しそうになったら、回り込むように誘導するとか

408403 :06/04/08 02:50
たぶんできてる。

idの死体があればtrue
function isDead( id )
local x , y = GetV( V_POSITION , 100000 - id )
return x ~= -1
end
これで即沸きを検出することもできるかな?

409403 :06/04/08 03:13
ごめんなさい
>>372と同じ勘違いしてましたorz
いい加減寝て頭冷やしながらいい方法考えます。

410(○口○*)さん :06/04/08 07:39
>>405
ケミへの追従&ユーザー指定だけなら、おっしゃるとおりなのですが・・・
「アクティブ索敵していると、壁向こうの敵に反応して固まる」
「体力消耗時に自動逃亡しようとしたとき、その逃亡ルートが移動不可セルでNG」
・・・といった、ホムが自律的に移動先を決める場合、問題になってます。

前者はともかく、後者はその「逃げる」行為に意味があるので、安息や待機ではちょっと目的未達。
#「速めに待機or移動で混戦から離脱させて、PPして即安息すればいい」っていえばその通りですが、
#その手間が命取りの可能性もありますし。

411(○口○*)さん :06/04/08 09:09
だだっ広い場所を選ぶとか、逃亡しなくてもすむ戦い方をすればいいんじゃないかな

412(○口○*)さん :06/04/08 09:32
ケミがホムのために動きを変えるのがイヤなんじゃないのか?
やっぱりAIである以上、自分でなるべく考えて動いてくれたほうが

413410 :06/04/08 10:10
>>411
せっかくAIを良くしようとして皆が集まってるスレなんですから、そういうところは
前向きに考えましょうよ。
もちろんおっしゃるとおり、プレイ技術でうまく戦うという手はあります。
でも、例えばピラ地下2でハンマーフォールを100%避ける自信はわたしにはないです。
人間はミスする生き物ですから。
#「ミスしたんだから、デスペナで仕方ないんじゃない?」といわれたらそれまでですが。

プレイスタイルで回避できるって言っていたら、基本AIだって「機能多すぎ」になっちゃいます。
ユーザーから操作がくる「移動・攻撃・スキル使用」に対応した3メッセージだけサポートできれば、
例えば追従移動がなくたって、「必要な時にコール・いらなくなったら安息」とか、
「常に平行して手動移動」で対応すればいいじゃない・・・でおしまいです(^^;;
ちょっとでも便利にしたいから、できそうなことはやりたい、ってことです。

414(○口○*)さん :06/04/08 11:44
1:「攻撃モーションの、最初の敵のIDを取得」→敵がいれば行動開始
2:「画面内の敵のIDを全て取得(デフォルト)」→敵のモーションによって行動開始
のって、どっちの処理が軽いのかな?

やばい、国家試験が近いんだけど、LuaとC言語がごっちゃになってるorz

415(○口○*)さん :06/04/08 11:53
if value != 0 then
...
end if

書いた次点で気づいたとはいえ本当に書いてしまった一文w

416(○口○*)さん :06/04/08 11:59
似たようなことやってるな・・・。
俺のはこっちだったが。
if value <> 0 then
...
end if

417(○口○*)さん :06/04/08 12:01
あるある(笑
コメントが /* */ とか // じゃなくて、 -- で始まるとか(^^;;

418(○口○*)さん :06/04/08 12:11
ピットマン狩りつつ地雷を検証してみた
・GetActors に地雷のIDは出ない(=地雷を攻撃できない)

・主人から4セル以上の距離で地雷をALT+クリック(orダブルクリック)
  →ホムが地雷の場所まで移動する(MOVE_CMD 発生)
  →主人が地雷から3セル離れた位置まで移動する 地□□□主

・主人から3セル以内の距離で地雷をALT+クリック(orダブルクリック)
  →ホムが地雷の場所まで移動する(MOVE_CMD 発生)
  →主人が地雷を攻撃しはじめる 地□□主

内部で主人と行動がクロスしてるってのは確かなようで
何故かホムにさせるべき攻撃を主人もやってしまってるようだ
そしてホム自身は攻撃できないのでPCクリックした時みたいに座標まで移動だけになっている
バグだよね

419(○口○*)さん :06/04/08 12:55
続いてID調べてみた
ID=57796 X=121 Y=60 HOMUNTYPE=(1620) MOTION=DAMAGE(4)
ID=42204 X=121 Y=60 HOMUNTYPE=(1620) MOTION=DAMAGE(4)
ID=42204 X=121 Y=60 HOMUNTYPE=(1620) MOTION=DEAD(3)
ID=42204 X=121 Y=60 HOMUNTYPE=(1620) MOTION=DEAD(3)
100000-57796=42204
問題なく出ている

ID=57717 X=121 Y=62 HOMUNTYPE=(1616) MOTION=DAMAGE(4)
ID=57717 X=121 Y=62 HOMUNTYPE=(1616) MOTION=ATTACK(2)
ID=42283 X=121 Y=62 TYPE=42283 HOMUNTYPE=(1616) MOTION=DEAD(3)
ID=42283 X=121 Y=62 TYPE=42283 HOMUNTYPE=(1616) MOTION=DEAD(3)
100000-57717=42283
こちらの場合死亡モーション中もmobは主人を狙い続け、
主人はさらに消滅してもまだ57717を狙い続けていたので
主人がタゲを移す暇がない即沸き対策は難しいかもしれない

しかし死亡モーション中のmobにはりつくのは防げそう

420(○口○*)さん :06/04/08 13:16
時にMobやPCのターゲットっていつ設定されていつかわる物なの?

いまいち内部状態の移り変わりが雑な気がする

421(○口○*)さん :06/04/08 14:52
>>420
Mobはアクティブなら索敵視野に入った時
ノンアクティブなら攻撃を受けダメージが1以上で解決されたとき
詠唱反応はPCのMOTION_CASTING検知した瞬間だね
近距離で攻撃されても、
ダメージが解決されるまでに詠唱感知したらそっちにタゲが行くのはそのせい

PCはカーソルをあててクリックした瞬間値が入る
攻撃モーションに入ってようが入って無かろうが関係なしやね
値が無くなるのはMOTION_DEAD取ったとき。

422(○口○*)さん :06/04/08 17:17
>>420が聞きたいのはV_TRAGETの仕様のことじゃないかな?

実際V_TRAGETの動作は相当雑な動きをしていますね。
対象が攻撃やスキルを使用したときに設定され、
設定された後は上書きされるまではリセットしないみたいです。
                      ~~~~~~~~~~~~
(例)
ID:50000の敵がホムを発見     V_TARGET 0
ID:50000の敵がホムを追跡     V_TARGET 0
ID:50000の敵がホムを攻撃     V_TARGET ホムID
ID:50000の敵が死亡         V_TARGET ホムID

ここで問題なのが、次に同IDの敵が画面内に来たときもV_TRAGETがホムIDを維持したままなこと。
対策をとって無いとホムが「自分がタゲられた」と判断して、いきなり画面端の敵を攻撃しに行く。

これはケミにも言えることで、敵を倒した後に、他の敵を攻撃する前に同IDの敵が
また画面内に現れるとホムが「主人が攻撃している」と判断してその敵を殴りにいったりする。

423(○口○*)さん :06/04/08 18:42
なるほど…。

てことは、同IDが湧いたときにタゲが残ってて突っ込んじゃうのを修正するには
毎回ダミーIDか何かを最後に仕込んでV_TARGETが0になるようにしとけばいいのかな?

424(○口○*)さん :06/04/08 21:05
ちょっとまとめてみた。おかしなところがあったら指摘お願い。

PC  ID=100001以上
            IsMon   HOMUNTYPE
プレイヤー  0(1)    専用            IDはプレイヤー固有。シーズモードではIsMonsterが1

NPC ID=100000以下
            IsMon   HOMUNTYPE
ホム        0(1)    ホム固有        HOMUNTYPEがPCとかぶる。シーズモードではIsMonsterが1
ペット       0       通常mobと同じ   
通常mob    1       通常mobと同じ
死亡mob    1       通常mobと同じ   (100000 - mobのID)のIDを出す。主にMOTION_DEADを出す
機雷瓶      1       通常mobと同じ   通常mobと判別できない
植物瓶      1       専用
その他      0       専用            人、看板、ワープポイント他

425(○口○*)さん :06/04/08 21:11
やっぱりそうか・・・

そうなる攻撃モーション中のターゲット以外は信用できないってわけだね・・・
使い終わったらちゃんと後片付けしなさい!

そんなんだからメモリリークなんて起こすんだよorz

426(○口○*)さん :06/04/09 00:15
>>413
別にAI弄りだけで頑張れるならそれでいいとおもう。
大体の人はそうしようとしてるみたいだし。
ただ、Gravityあたりに「侵入不可」情報返すように依頼する、とかいう意見は
たぶん>>411みたいな理由で蹴られるだろうな。

427(○口○*)さん :06/04/09 00:50
だいぶスレの進行が遅くなって来たなぁ。
これなら、雑談スレと一緒にしても良いかもしれん。
 
よし。ネタ投下。
AI開発者に問う。
今のホムのレベルは、いくつ?!
 
俺まだ36!
orz

428(*○口○)さん :06/04/09 01:04
ホムンクルス用モンスターデータライブラリmobdata.lua
配布場所を変更しました。
変更先>>http://himenomikoto.at.infoseek.co.jp/kulus_project/


ホムンクルス用MAPライブラリ
in_sphinx1.lua(スフィンクスダンジョン1F)
配布場所>上記URL先

MAP[x][y] -- 座標[x,y]が進入可能セルかどうか yes -> 1 no -> 0


ようやく終わったorz
壁向こうの敵にロックしやすく入り組んでいるマップで選んだけど
PD2の方が小さくてよかったなと後悔;;
移動チェックアルゴリズム等の参考にどうぞ

429(○口○*)さん :06/04/09 01:06
>>427
俺は、国家試験が近いから4月なってから休止してるけど、鳥でLv49だな。
すでに、鳥のStr70が達成してていい感じだ。ミノで一緒に狩りしてる。
ちなみに主人は、74/39。入る経験値%が鳥とほぼ一緒でミノ1匹につき、
0.5%前後ぐらいかな。>牛いいよ牛

430Glenelgの人。 :06/04/09 01:07
マイナーAI作者ですが。
地道に鍛えてバニルLv52。

アルデバラン↓↓で、森に埋もれた草を刈りだすための機能を付けつつ(笑)、
草刈りながら育ててます。

431(1/2) :06/04/09 01:11
178 :(^ー^*)ノ〜さん :06/04/04 13:17 ID:OUL0033O
ホムって基本的には攻撃する時攻撃モーションキャンセルして、
ものすごい挙動不審にブルブル震えて攻撃してるけど、
たまーに攻撃モーション最後まで表示されるよね?
毎回ちゃんとした攻撃モーションを出すように出来れば本来のASPDになるのかな。
この辺AIじゃどうにもならない?


180 :(^ー^*)ノ〜さん :06/04/04 13:32 ID:A1XFvLNo
>>178
モーションをしっかり表示させるだけなら攻撃に周期付ければ出来るよ
150ms位で出来る(見える)ことは確認してる。
基本的に攻撃命令を飛ばしてるのはクライアント側のAIだから。

ASPDに関しては>>98-102で検証されてるとおりで、
結論に有るとおり今見えてる攻撃は実際のASPDより"遅い"ってことになる。
キョドってるのは攻撃→ディレイ→攻撃
のディレイ時に次の攻撃をしようとして処理出来ずキャンセルされた結果だと思う

432(2/2) :06/04/09 01:11
730 :(^ー^*)ノ〜さん :06/04/06 00:35 ID:G4wV/D/E
>>180
すっごい今さらだけど…
150msの周期を持たせるのって、
AIのどのfunctionに何て書けばよいの?
モーションしっかり表示を実現させたいー


731 :(^ー^*)ノ〜さん :06/04/06 00:41 ID:g5Rtqt2/
AIスレで聞いたほうがいいと思うが…。

ケミに等速追従するっていう機能があるだろ。
あれで付加軽減版とか称してるタイプがあるが、ヒントはあれだ。

Attakコマンドが実行されるときにグローバル変数へGetTickで値を取得し、
そこで取得した「前回攻撃したときの時刻」にインターバルの時間をプラスした値が
現在時間以下になったとき、という条件分岐でAttackコマンドを囲めばいい。

---------

上記のようなやりとりがありまして、誘導されました。
モーションしっかり表示をさせたいのですが、結局どこに何を書いたらよいのかわかりません…。
分かる方いらっしゃいましたら教えていただけませんか?
AIは0-MATERIALのどきどきAIを使ってます。

433(○口○*)さん :06/04/09 01:29
>>432
AI雑談スレに最近あったと思うけど、せっかくだから
改造ポイントわからない人向けのコードを。
Attack関数そのものにスキルディレイもどき
(一定時間内はAttack命令を無視する)を設けるというもの。
場所はAI.luaの末尾でも、いっそUtil.luaの末尾にいれてしまっても。

do
local attack_delay = 150 --ミリ秒。要調整
local attacked_tick = 0
local _attack = Attack
function Attack(id1, id2)
if GetTick() - attacked_tick < attack_delay then
return
end
attacked_tick = GetTick()
_attack(id1, id2)
end
end

デバッグはしてない。間違ってたらごめん。
これでもわからなかったらAI雑談スレ行くといいかも。

434(○口○*)さん :06/04/09 01:32
>>428
調査おつ&感謝。
マップデータを秀丸で「折り返し1000桁」「表示フォントサイズ3」とかでみると
地図がくっきり浮かび上がって美しい。
↑使い方が違うと突っ込まないように(笑)

435(○口○*)さん :06/04/09 01:42
前にちょっと話題になった「Lua 明示的グローバル変数宣言モジュール」と
同様のライブラリを書いてみました。
デバッグもドキュメントの練り込みも足りないけれども…。
http://www5e.biglobe.ne.jp/~akemino/upload/mmobbs/files/3044.zip

436(○口○*)さん :06/04/09 01:46
ちなみにこれを作ってから、Programming Lua:14.2にまったく同じものが
見つけてしまったという曰く付き。orz
でもこのライブラリの方がちょっと高級なはず。

437432 :06/04/09 01:47
>>433
実際にやってみたところ、
AI.luaの末尾に追加することでモーションをしっかり表示させることができました。
(Util.luaでは変化なしでした)

ありがとうございました!

438(○口○*)さん :06/04/09 02:15
>>437
まぁまったく同じものが雑談スレにあったんだがな

564 名前:(○口○*)さん[sage] 投稿日:06/04/07 14:26 ID:r7urR5aK
>>563
ケミスレにも書いてなかった?

--global
AttackTime = 0
A_Intarval = 150

--ATTACK_ST

if (MySkill == 0) then
    Attack (MyID,MyEnemy)
else
ってなってるとこを
if (MySkill == 0) then
    if (GetTick() - AttackTime >= A_Intarval) then
        Attack (MyID,MyEnemy)
        AttackTime = GetTick()
    end
else

簡単にはこうやれば。

439(○口○*)さん :06/04/09 02:18
あ。組み込み場所を探さなくていいように仕込んであるのか。

440(○口○*)さん :06/04/09 07:50
>>428さんのをどう使ったらいいのか
もうすこし噛み砕いて説明してほしいっす><

441(○口○*)さん :06/04/09 09:28
>>440
データが詰まってるから勝手に使ってね!
って感じかな

requireで読み込んでMAP[x][y]に1or0が入ってるからそこから好きに読み込んで使えばいい

用は地図が入ってるから後はホムにその地図を読める機能を組み込めばOK
地図を読む機能はまだ作られてない

442(*○口○)さん :06/04/09 09:44
in_sphinx1.luaは「その座標に立てるかどうか」が、
立てる> 1
立てない> 0
で配列に格納されてる物
座標[x,y]が進入可能セルかどうかは
local Mcheck = MAP[x][y] -- とすればMcheckに1か0のどちらかが入る

以上

自分の居る座標から指定した座標へ移動可能かどうかは
[100,200] -> [110,200]ならMAP[100][200]〜MAP[110][200]の値が
すべて1か、0が1つも無い事をチェックするのがまず初め
斜めの移動や、迂回可能な障害物の判定は各自の知識と発想、ホムへの愛が試される(違

正直な所、作ったはいいけどアルゴがむず過ぎて扱いきれてない(汗
基本的な移動可能範囲はプレイヤーと同じだから、障害物の形状、配置
プレイヤーの位置、目的地の位置は実際に壁の側とか歩き回ってみるのがいい

443(○口○*)さん :06/04/09 10:14
とりあえずROの移動の基本は
「目標地点と現状位置とのx軸・y軸のそれぞれについて、差があればつめる」というもの。
なので「障害物がなにもなければ」Move()でホムが移動するルートをチェックするのは、
そんなに難しくない。

「どれくらいの障害物がある」ときに、「どういうルートを取るか」・・・という判断方法が課題かな。

444(○口○*)さん :06/04/09 14:26
壁・崖越しにいるPCやNPCを選択肢から除外するのはできそうだね

445(○口○*)さん :06/04/09 14:53
>>427
マイナーAIの作成配布者だけど
バニルでまだ25
低級狩場でこつこつデバックしてるから上がらない
|||orz

446(○口○*)さん :06/04/09 20:00
>>438
150のインターバルってホムの攻撃モーションが終わるまでの時間ですか?
これはホムのASPDが上昇しても変わらないってことなのかな
とするとこれを導入すると、羊のような低ASPDならまだしも、鳥だと攻撃速度遅くなることがある?

447(○口○*)さん :06/04/09 20:39
そのくらい自分で調整しようよ。

448(○口○*)さん :06/04/09 20:51
いや、でも150のインターバルを変えるとモーションが正しく表示されないんだ
つまりモーションはキャラとは違ってASPDで時間が変化しないってことかどうかを確認したかったんだが

449(○口○*)さん :06/04/09 21:11
どんな早くてもせいぜい秒間3発くらいだから150msで遅いってこたないと思うよ

450(○口○*)さん :06/04/09 21:15
MAXと言われてるAPSD190でも秒間5発くらいだっけ?
周期が150msなら秒間6発半ってとこだろうからこっちのが全然早い。
APSDより遅れるってことは無いと思う。

451(○口○*)さん :06/04/09 21:16
固い雑魚敵なぐらせて、単位時間辺りの攻撃回数調べればよくね?
やりたいのは、ASPD落ちない範囲でのモーション表示だろうから、モーションに変化があるかどうかより
ASPD落ちてるかどうかを調べたほうが楽。

452(○口○*)さん :06/04/09 21:21
>>449-450
丁寧に答えてくれてありがとうございます
攻撃モーションの時間はホムのASPDに依存しない150固定、これより早く攻撃するには秒間約6発以上なので
ならこれからASPDが成長しても調整する必要はないってことですね
今夜は良く眠れそうです

453(○口○*)さん :06/04/09 23:59
>>451がすこし不憫なのでオイラはそれを参考にさせてもらいます

454(○口○*)さん :06/04/10 00:02
けど確かに、150で長すぎるってことはまずないとおもうんだが、
150の待ち時間だけじゃなくて他の命令とかの処理時間もあるから、
一度くらいは調べてみてもいいかもしれないな

455(○口○*)さん :06/04/10 00:22
AI()が呼ばれる周期がそもそも100msとかそのぐらいだから
これ以上はあんまり意味ないっぽい

456(○口○*)さん :06/04/10 00:24
たとえば秒間4回攻撃のASPDだったとすると、攻撃サイクルが250ミリ秒
150ミリ秒に設定すると一回目はディレイ中だから無視、300ミリ秒に一回攻撃することになるようなきがする
やっぱ最速で命令だしとかないと若干損するんじゃね?

457(○口○*)さん :06/04/10 01:14
2HQや二刀、狂気ポットのないホムは秒間4発以上はちょっと無理だろうから
300msでも充分だとは思うんだけどな
AI()の呼び出し間隔は変わらないのだから短くしてもあまり変わらないと思う
攻撃命令をディレイ中もやろうとしてるのがおかしいんだよなあ

458(○口○*)さん :06/04/10 01:20
実ASPDに見合った値をいれない限りは、どうやっても損をするか
無意味になるよ。
あくまでもこれは「効率<見た目」の人のためのコード。

459(○口○*)さん :06/04/10 01:36
>>458
それを前提として皆話してるよ

460(○口○*)さん :06/04/10 02:04
AI()呼び出し周期:100ms一定
Attackインターバル:150ms
ASPDによる攻撃ディレイ:250ms
t:経過時間(ms)
とする。

まずAI()周期から、Attackインターバルは200msと同じと見なせる。
(150<=t<200でAttack()されることはないから)

t=0:攻撃
t=100:Attackインターバル
t=200:ASPDによるディレイ(Attackインターバル再設定)
t=300:Attackインターバル
t=400:攻撃

実質上は400ms周期でしか攻撃できなくなる。

この問題を軽減するためには、インターバルを可能な範囲で
絞る必要がある。けれどもAI()呼び出し周期よりは長くしないと
コード自体が無意味になる。

上記の例だと201ms〜300msでならロスがでない。
けれどももしAI()周期が120msなら、〜240msも同様のロスを起こす。
AI()周期の揺らぎがあることを考えると、結局250msピンポイント以外は
ロスの原因になる。

よって>>458

461(○口○*)さん :06/04/10 02:12
うん。ただ458の書き方だと、他の人が「周期短くすればaspd上がる」
って書いてるのがおかしい、と指摘してるみたいだけど、結局は
その「損しない指定値はいくつなんだろうね」について話してるだけなんで。
だれも>>458に反する話はしてないよってこと。

まぁその仮定から導き出した250も、あくまで仮定ではあるんだけどね。

462(○口○*)さん :06/04/10 02:32
一カ所訂正。
250〜300ms指定(ASPD周期以上、AI周期の倍数以下)は
ロスが比較的少なくて済む。
けれどもやはりASPD依存。ASPDが301ms〜だったらこの指定は逆効果。

>>461
説明端折ったらああなったというか、なんというかすまんかった。

実ASPDの算出方法と(個々人の)平均AI()周期がわかれば
計算からその人の最適値を出すことができるだろうけどね。

でも150msでモーションがきれいに出るのなら、最適値以外で
150ms指定よりも良い結果になることはないんじゃない?

463(○口○*)さん :06/04/10 09:28
モーションをきれいに表示させることが目的なら
モーションと同じ時間のディレイを掛ければいい

モーションが終わってから次のAI()が呼ばれるまでのロスは
どうあがこうと消すことは出来ないのだから
モーション表示にかかる時間を計算するしかない

モーションの表示時間=全ての環境での最適値

それより小さくすればモーションが途切れる可能性がでるし
それより大きくすればロスが生まれる可能性が出る

464(○口○*)さん :06/04/10 09:39
ってよく見たら
ASPD>>モーション表示
でFAでてるのか

だとすればモーション時間の変わりにASPDの時間に収束される
別にちょうどである必要は無いASPDの時間さえ越えていれば
次にAI()が呼ばれた時点で攻撃すればいいのだから

465140 :06/04/10 10:45
SelectActorsの人ですこんにちは
(前略)そのせつはお世話に(後略)

実験した結果
OD程度のMH狩りには影響なし
プロ十字路もアドバイスのおかげで余裕

と言うわけで公開してみようかと思うんだけど
関数郡だけ公開
一部の条件でID取得するところまで公開
GetMyEnemyの代わりに組み込んでるところまで公開

どれがいいだろうか
新しい機能ってわけじゃなくてただわかりやすくするだけのものだから関数だけでいいかとおもったんだけど
それだと誰にも使われそうにない(笑)

466(○口○*)さん :06/04/10 11:21
使用対象が初心者なら、初心者が落として、何も弄らず使用できる状態。
使用対象が中級者なら、関数郡だけ。

使用者の想定次第じゃないだろうか。
公開方法1つである必要もないし。

467(○口○*)さん :06/04/10 16:40
攻撃モーションに入ってしまうとモーション終るまでAI()走って無いかも。

攻撃モーション中はattackコマンド使わないとかテストしてたら
自ホムのモーションがMOTION_ATTACKでは回ってこなかった
(MOTION_STANDとかMOTION_MOVE。ダメージとかは受ける状態でテストしてない)

attack実行直後まだ立ち状態でAI()走って来て
攻撃モーション表示されかけで次のattackでキャンセルされてMOTION_STAND?
以降攻撃ディレイ中にattack連続でぷるぷるー

デフォルト状態でもモーション終るまで表示される事があるのは
キャンセルが間に合わなかったとか?

クライアントの内部的に攻撃モーションに移るまで待つだけとか150ms?

貧弱マシンだから状態取り切れて無いとは思わないけど、
高性能なマシンで調べてみないとダメなのかな

468(○口○*)さん :06/04/10 16:58
>>467
>>173 とかもあるけど、
アタック中だけではなく、通常時も150ms前後あとにAI()関数呼ばれてない?

ホムの Attack() 中に AI() が呼ばれないじゃなくて、
ホムの MOTION_ATTACK が V_MOTION で取れない気がするんだ。

それに、AI()が走らないのなら、
そもそもモーションキャンセルが起こらないと思う。

469(○口○*)さん :06/04/10 17:48
ホムの射程変わった?
もしくはAttackInSight(だっけ?)の仕様が変わった?

デフォAIだとMobから3セルの位置に誘導すると
ぴくぴく動きながら攻撃しようとしてるようなんだよ
射程は2セル(+桂馬)らしく攻撃できてない
前からだっけ?

470(○口○*)さん :06/04/10 17:54
最初っからの気がする

471(○口○*)さん :06/04/10 20:49
>>469
俺んとこのは、最初からそうだし今でもそうだ(^^;

472(○口○*)さん :06/04/10 21:13
それは重力座標
デフォAIだと距離1セル以内じゃないと攻撃しない

473(○口○*)さん :06/04/10 21:42
>>467
AI()でデバッグ書き出しして見てみたら(対象:草)
attackコマンドのwait入れない(デフォルトのぷるぷる)だと
殴ってる間ずっとアタックのプロセスで回ってた。

wait入れて叩かせるとアタックプロセスは殴った回数x2
attackコマンドとwait判定やった後AI()自体回って来て無いですね

モーションキャンセルはattackのリクエスト、クライアント側の受付から状態変更までに
AI()がまだ走ってるから実際状態が変る前に、
再度attack出されてるからキャンセルかかってると思います

MyStateとホムのモーション、経過時間だけですが
たれ流ししてたらHDDアクセスしっぱなしできつい…

474(○口○*)さん :06/04/10 21:43
ごめん >>467でなくて>>468 orz

475140 :06/04/10 23:29
とりあえず動作確認の出来たSelectActors置いておきます。
http://www.mmobbs.com/uploader/files/135.zip

コレ組み入れたからどうだって物はないけど適当に使ってやってくださいませ
直で中身を呼ぶもよしSelctActors使うもよし例で乗っけたGet系使うもよし

ps.やっぱりコード用にプレーンテキスト乗っけれるうpろだほしいですね

476(○口○*)さん :06/04/11 01:11
>>469
前から。
かなり前にこのスレ関係でホムの攻撃範囲調べて書き込んだから間違いない。

3マス離れてるのに殴ろうとするのは、

サーバー上の座標は
□□□□□□□
□□モ□□ホ□(距離3)
□主□□□□□

画面上の見た目は
□□□□□□□
□□[ モ ]□ホ□
□主□□□□□
(2マスの間にいるように見える)

このときのクライアント上の座標(V_POSITIONでの座標)が
□□□□□□□
□□□モ□ホ□(距離2)
□主□□□□□

となっているために起こってるんだと思う。
デフォAIだと、3マス離れてたら接近しようとして動くはず。

>>472
デフォAIはホムから2*2まで攻撃する。
ホムの通常攻撃の射程もこの範囲。

477(○口○*)さん :06/04/11 01:13
>>476
モーホーまで読んだ

とか言わせたいんだろう言わせたいんだろう。

478(○口○*)さん :06/04/11 02:07
主要なバグの殆どは鯖とクライアントでの座標ズレから来てるな
人居なくなっちまって修正できないんだろうけど
はなしになんねーよな・・・(´・ω・`)

ホムの座標取得しようとするとクライアント上の値返されるもんな
ムーンライト何度不発させたと思ってやがる、癌シネ
のーみそ足りない俺には上手い方法見つからん
方針変えてみっか……

479(○口○*)さん :06/04/11 02:12
>>475
関数部だけアルケミWikiのライブラリに載せる手もある

480(○口○*)さん :06/04/11 02:30
>>478
ムーンライトってかスキルって敵座標みてるんかな?
敵IDさえ指定してりゃ、斜線とおってるなら多少離れてても
発動するもんだとおもってた

481(○口○*)さん :06/04/11 07:19
>>480
敵とホムとの間が多少離れてて、その合間に障害物があると不発する訳だ
ID見て放ってるせいなのだが。

482(○口○*)さん :06/04/11 09:13
>射線通ってるなら
って書いてあるから、まぁ>>480で合ってるな
変換ミスってるけど。

483(○口○*)さん :06/04/11 09:26
ROの開発時は昔のISDN世代メインで動くように作られてた時代だからね
ダイヤルアップも大勢いたし
データを簡易に扱って、画面上のみ補間計算で滑らかにごまかす。
そういう設計思想はネトゲでは必要だった
同期させるには当時の設備じゃ向こうもこっちも無理があったんだよ

ホムAIのMove連打ですら今の設備でネットワークに不調が出るほどなんだし
わざわざメンテ延長したりね
それこそ座標取得のためのコマンドを秒間何百も垂れ流したらパンクするんじゃない?
あとホムAIはサーバーとの同期をとってないからクラ以外からの情報取得はあきらめたほうがいいと思う
ここは人間がどうやってずれを感知してそれを修正してるのか
ほとんど無意識の領域になってるけどそれの再現が正しいアプローチかと

とここで、大事なことを思い出す
人間に見えててホムに見えてないものが多すぎるorz
・進入不可セル
・行動(間に挟まるStandモーションが邪魔すぎ)
・結果(ダメMiss表示)

484(○口○*)さん :06/04/11 12:57
やつらもマップデータ用意してるわけで・・・
同じ事だと。

485(○口○*)さん :06/04/11 13:11
>>483
移動やら、MOBの攻撃判定とかでちゃっかり取ってるやん。
別にサーバーで正確な判定返してくれなくても、
クライアントで射程通るか見てくれるだけで大分違うし。

486(○口○*)さん :06/04/11 13:43
>>483
重力座標の原因の大半は、ヒットストップ処理が鯖とクラそれぞれで
行われることじゃないかな。(ヒットストップ自体は鯖だけだっけ?)
つまりヒットストップが起こる状況があったときに、クラが座標を
要求するだけでだいぶ改善されるはず。
そうでなくても、攻撃指示パケットが射程外のせいで破棄されたときに
鯖がついでに正しい座標を返してやれば座標の同期が取れる。
(チート対策に、視野範囲内mobならばという条件がいるけれども)

常に同期を取ろうとするなら、たしかに設備の問題は出てくる。
でも要所で行える工夫まで省く理由としては弱いよ。

>ホムAIのMove連打ですら今の設備でネットワークに不調が出るほど
ソースplz

487(○口○*)さん :06/04/11 13:51
射程通る?
どっちのことかわからないけど

射程が届くだった場合
Mobからの攻撃判定やMobの移動とかは全部サーバー処理
逆にこっちから攻撃したりする場合はクライアント座標見てるからずれが起こってる
向こうから座標を送ってくるのは移動開始時点の始点と終点だけ

射線が通るだった場合
↑で言ってるのは座標ずれについてはあきらめるしかないという話
射線が通るかまたは進入不可セルの判定関数は追加実装必須だと思う
クライアントは射線処理してたっけ?
移動不可セルの情報は確実に持っているようだから
こっちの取得関数実装のほうが現実的かな

488(○口○*)さん :06/04/11 13:51
韓国ってISDNそんなに普及してたの?DSLだと思ってた
日本でもYBBとセットが推奨だったかと

489(○口○*)さん :06/04/11 13:52
なんかAIの話からずれてきたなw

490(○口○*)さん :06/04/11 14:47
確かにずれまくってはいるけどw
組み込み言語で親の動作を制御するって言うんだから
親の仕様がわからないことにはねぇ

>>448
開発開始時期がすでにいまから5年以上前なんだ
普及の遅かった日本ではADSLが話題になる前の話
NTTのフレッツADSLの正式サービス開始が2001年だったはず
でも韓国ではかなり早かったって言うしそのころにはもう普及してたのかな?

俺も年を食うはずだorz

491(○口○*)さん :06/04/11 15:01
>>487
どちらにしろサーバー処理だろ?
今と何が違うんだ?

うちは斜線通るかぐらい、クライアントでチェックして欲しいといってるんだぞ?

492(○口○*)さん :06/04/11 15:05
すまん>>448
正しくは>>488

>>486
そういえば途中でヒットストップの仕様が変わったんだったね
ずれが起こるのは被弾、スキル攻撃使用等の移動キャンセル時だけだから
そのときだけ同期をとるようにすれば良いわけか

といってもこっちじゃどうしようもない・・・

493(○口○*)さん :06/04/11 16:25
>>491
>移動やら、MOBの攻撃判定とかでちゃっかり取ってるやん。
について何のことかわからんかった
>射程通る
が射線の話であれば同意と言ったつもりだったんだけど

まぁ、意味無く熱くなってるからここらでやめとくw

494(○口○*)さん :06/04/11 17:28
>>493
むしろレスすることに驚いたわけだが。
意味わからん文にはレス自体しないほうがいいぞ?

495(○口○*)さん :06/04/11 17:41
ここはAIについて語るスレであって、クライアントに追加して欲しい
機能について語る場所じゃない。その辺で(ry

496(○口○*)さん :06/04/11 20:42
まったくだ。
AI雑談スレの方が、よっぽどまじめにAIについて語ってるぜ。

497(○口○*)さん :06/04/11 22:21
>>496
まぁ落ち着くんだ。何もふざけて語り合ってるわけじゃないんだしさ。

498(○口○*)さん :06/04/11 23:42
>>497
まぁまぁ、おまいも落ち着け。
496の発言時点でのAI雑談スレのレスを
落ち着いて良く見てみれw

499(○口○*)さん :06/04/12 00:55
>>478







500(○口○*)さん :06/04/12 01:02
>>499
釣られてるよwww

501(○口○*)さん :06/04/12 03:58
>>499
言われるまで気付かなかった。

ところで、状態による分岐をしないで
常に同じ処理を繰り返すAIってのを考えてるんだけど、
これって非現実的なんだろうか。

待機中だけじゃなくて、追尾中も追跡中も戦闘中も、
常に索敵をしてほしいとか思ったり。
で、実装してみたのはいいけど、
そんなことするなら分岐する意味ないなと。

目下、最大の問題だと思ってるのは処理速度。
気のせいかもしれないけど、攻撃速度が落ちてるように見える…。
デフォAIと比較して測定しようにも、
常にある程度ラグいから、全然分からん。

502(○口○*)さん :06/04/12 04:18
>>501
索敵って画面中のActorリスト毎回取得して回す訳じゃない
結構処理としては重い部類だと思うのね

毎回やってたらAI回る速度が遅くなってもおかしくねーんじゃねぇかな
今、AIの呼び出し周期って100ms位じゃなかったっけ

あと、戦闘中は基本的に同じ相手殴り続けるだけだし、索敵処理入れるのは勿体無いと思う

もし攻撃毎に最も優先すべき攻撃対象探すんなら
攻撃命令出した直後に次回攻撃対象探す索敵処理入れておけば
攻撃ディレイ中に索敵できるんじゃねーかな

503(○口○*)さん :06/04/12 09:01
>>501
状態処理エンジンって、要は「自分の状態を定義することで、現状やるべきことを絞り込む」
設計手法なので、それで不利かな、と思うのなら別にそれにこだわる必要はないと思います。
たしかに常に全体索敵してその状況だけで判断するのなら、いらないといえばいらない仕組みですし。
実際元AIでCHASEとATTACKで最初のほうは同じなので、無駄といえば無駄。
(敵が視界内にいるか、射程内にいるかとか)

ちなみに拙作AIでは、状態に関係なく常に周囲の索敵は実施していますが、
体感ではそんなに性能が落ちたとは思いません。まああくまで「体感では」なので、
わたしが鈍いだけかもしれないですけど。
ttp://tomose.dynalias.net/RO/index.php?%A5%DB%A5%E0%A5%F3%A5%AF%A5%EB%A5%B9AI

504(○口○*)さん :06/04/12 09:25
mobdata.luaのフローラとジオなんだけど、
位置固定が0になってるのは正しいのかな。
確かに枝で出したら移動するけど・・

505(○口○*)さん :06/04/12 09:50
策敵1回に付きGetActors()4回+SelectActorsを計28回呼んでる
(優先順位ごとに4種類x1種類とってくるのに判定ループ7回)
これを策敵モードのときだけまわしてるけど
他のときに比べて策敵時に重くなるってことは無かった

>>341-355
このあたりの流れで自分が言われたようにやってみなければわからない
AI()自体が常時最高速で回ってるわけじゃなくて100〜150msに1度しか呼ばれないみたいだし

たとえばゲームで最適化されているFPS60を出そうとすると
1回の処理を16msで終わらせないといけない
だけど重そうなゲームでも結構それを実現してるところを見ると
150msもあればこの程度問題になるようなことは無いんじゃないかな

506370 :06/04/12 12:02
>103,104,370,382,403,419,424
の流れで。

敵ロスト判定後の索敵時に死亡mobID(100,000-ロストmobID)
を除外するAIを組んでみた。

やばい
めちゃくちゃ判定が早くなって休みなしに次々いくもんだから
ほとんど自然回復しなくなってPP依存度がめっちゃあがった。

だまされたとおもってつけてみ?
先行攻撃タイプのホムだとあきらかに動きが変わる
キビキビ動きすぎてこっちが保たない

>382
すげぇ発見だったぞ〜、摘要できた狩り場ではめちゃくちゃ有効だった。
後は各狩り場での検証次第だ。
まだアイン近辺の2〜3MAPでしか試してないが摘要外はみつかっていない。

507(○口○*)さん :06/04/12 12:28
>>380,506
正直にいって、380の報告見たときには別に気にしていなかったんだが、結構有効なんだね。
うちも試してみるよ・・・今は仕事だから、夜だけどな〜(笑)

でさ。それを見ててふと思ったんだけど・・・
1000000 - <敵ID> == <死体ID> ってことだよね?
これに関連して、「敵IDは50000以下」「死体IDは50000以上」ってのは成り立つのかな?
もし敵IDが無作為に割り当てられているのなら、50000以上のIDを持つ敵が死ぬと
それの死体のIDが「既存の他の」敵IDと衝突するリスクがあるから、なんかこういう線引きが
できそうな気がして。

私のAIは事前に全体索敵する動きをしているので、個別の死体IDを当面の死体として
切り捨てるよりも「値域的にこのObjectは死体」ってわかったほうがうれしいので。
そういう調査の仕組みをはめこんで試してみようとは思うけど、もし誰か調査ネタあればうれしいかな。

508507 :06/04/12 12:32
めいっぱいリンク先ミス・・・

>>380,506

>>308,506
で。

大発見者に申し訳ない oTL

509507 :06/04/12 12:40
・・・俺、ダメだ・・・
382氏だよね・・・ごめん・・・

510(○口○*)さん :06/04/12 12:56
同じく調べられないんだけど、この一見妙な実装に筋を通すとしたら
ID - 50000 = ±mob内部ID
ということをしていて、それの符号で生死判断してるんじゃないかな。
もしその仮説が正しいなら、生きているmobのIDは50000以上に
なっているのが自然。

"100000"が2の倍数だったなら、ビット処理の結果だとわかるんだけどな…。

あとちょっとだけ思ったのが、死亡モーションには鯖はまったく無関係で
クラが勝手にでたらめなID(100000-ID)振っててきとーに処理してる可能性。

511(○口○*)さん :06/04/12 12:58
>>507
まあミスがここでよかったじゃないか。
仕事で大きなミスしないようにね。

512(○口○*)さん :06/04/12 13:00
>>507
>これに関連して、「敵IDは50000以下」「死体IDは50000以上」ってのは成り立つのかな?
逆逆。

ざっと調べた感じだと、「敵IDは50000台」「死体IDは40000台」だった。
6万、7万はあるかもしれないけど、5万が一つのボーダーラインだとは思う。

513(○口○*)さん :06/04/12 14:45
クライアント側で適当に死体オブジェクトとIDを作ってる可能性は高いね
でも、同じIDあるとバグるからたぶん「使われていないID範囲」を使っていると思う
そうなるとどっちにしても「5万以上のみ」の条件で死体Mobと生きたMobは振分できるでFA出そう

514(○口○*)さん :06/04/12 16:33
4万台の生きてる敵を下水で発見。

id=49640 h_type=1051(盜蟲)
id=44752 h_type=1051(盜蟲)

死体は100000ルールで出てきたけど、
4万台をターゲットから外すのはちょっと待ったほうがよさげ。

515(○口○*)さん :06/04/12 18:01
ってことは5万台の死体が出来たってこと?

516(*○口○)さん :06/04/12 18:20
プロ水路1Fテレポでざっと回ったら68ID拾えた
846、2241、4096、5579、5632、5827
6186、6311、7243、7679、9194
10000、20000、30000、30000、40000台

元の数がファミリアー20、盗蟲の卵90、盗蟲40、タロウ20
だから卵から孵化したゴキ(一度に4匹出る)だと思われる
枝mobも試してみたら5万以下(6931)が出たのと
群れbossの取り巻きが同様に5万以下だった事から
孵化変化、サモン(取り巻き)のIDは4万以下のランダムだと思われる

って言うか落ち着いて考えたら当たり前のことだったんだな・・・
ホムがMAP出現時にランダムID振られるんだから枝他もランダム・・・

>>515
死体オブジェクトは本体が49640なら50360が出るし、846なら99154が出る

517(○口○*)さん :06/04/12 18:48
とりあえずPCとNPCの区別はほぼ確定、
mobの死亡中判定はMOTON_DEADと10万ルールである程度できそうだね

518(○口○*)さん :06/04/12 19:23
そうか・・・沸き固定mobだけか

確かに、枝・取り巻き・羽化・分裂(土精)
これらは少しずつ仕様が違うのが何種類もあるけど
元は全部「サモンモンスター」スキルだからね(たぶんGMが使うのが元祖)

前回取得時のactors取っておいて差分を10万ルールで判定するしかないのかな
なんかスマートじゃないねぇ
でも、そうなるとクライアントはID重複の可能性はどう処理してるんだろう?

519(*○口○)さん :06/04/12 20:11
10万ルールはケミとホムが倒した死体objなら判定しやすいけど
多人数PTで行った時とか画面外から他PCに確殺された時(タゲが残らない)
なんかだとちょっと判定が面倒になるね

>>518
ランダムといってもIDを割り振るのはサーバーだから
被らない様に(死体objも)調節はしてると思うよ

520(○口○*)さん :06/04/12 21:26
となると
ランダム生成のときに使用済み&その反転IDが出ないように判定してる?
もしくはハッシュ化してかぶったらずらすとかしてるのかな?

前者は作るほうの意見とするとありえないとしか言いようがないな・・・
となるとやっぱり乱数mobが死んだり沸いたりするたびにずらされるのかな?
1度でいいから反転++1とかが取れればコレで決まりなんだけど

反転ルール自体が正確じゃないことになるからAI作る側としては痛いw
可能性自体が万にひとつだからほっといてもいいかなぁ

521(○口○*)さん :06/04/12 21:38
相手は重力だからな。
万が一だからほっといてる可能性を否定できない。

522(○口○*)さん :06/04/12 22:15
ちょっと確認して良かですか。
 
現在進行形の話題は、
敵が死んだ直後に
一旦MOTION_STAND状態の別IDで現れてから
MOTION_DEAD状態になって消えていくため、
敵探索の時に
死んで消えて行く敵を拾ってしまい、
それをホムが攻撃しようとして止まるのを
直そうとしてる、と言う事でOK?

523(○口○*)さん :06/04/12 23:17
>>522
STANDに限らずDEAD以外の全般だろうね
こっちではダメージモーションがそのまま死体に引き継がれてたログもあるし

mobが死亡中の点滅になってる死体オブジェクトはDEADが主に出るけど
STANDやそれ以外にも変化するしDEAD自体がGetVで拾いきれないこともあるだろうから
「標的のmobが死んだ」って判定を10万ルールでもしようってことだろう

死体が出てるのはせいぜい数秒間だけだから死体IDを10秒くらい保存して消えるようにしときゃなんとかなんないかな?
うちでやってる判定は直前にターゲットにしてたmobのIDを次に標的になる候補のmobIDとを
10万ルールで比較してるだけなんで複数でてきたら認識できないな

524522 :06/04/12 23:40
DEADになった後、さらに別の状態に変化するのか〜なるほど。

と思って、状態調べてきたら一度DEADになったら、
消えるまでずっとDEADな感じ何だけど、とり方の問題かな・・・

死んだ後、STAND→DAED→STANDとか成ります?>状態取ってる方

525(○口○*)さん :06/04/13 02:44
ホムが死体食べてる時間邪魔しちゃ可哀想だよ

526(○口○*)さん :06/04/13 06:33
(゚Д゚;)・・・・




(゚Д゚)

527(○口○*)さん :06/04/13 09:36
ホムのモーションをどうにかなくしてASPD190にしたりするチートの存在はありえなくもない?
仮にこれがあるとして広まったら、現在表示されている正常な遅ASPDが適応されて
効率が格段にさがりそうだ

528(○口○*)さん :06/04/13 10:14
>>524
うちの環境でも、一度DAEDになったらそのまま。
ただ、DAEDになる前の状態で止まることもあるっぽいから、死体判定は何かと欲しいところ。
まあ、死亡判定は座標で取れるから、問題になるのは索敵時だけで、あまり気にしてないけど。

そういえば、画面内にMOBの残骸残った場合の処理とか考えてないな・・・。
そんな激しいMAP行かないから忘れてた。

529(○口○*)さん :06/04/13 10:19
投稿してから違和感に気付いたぜ・・・deadだな!
こんなんだから nil エラーばっかり出るんだよな・・・。

530(○口○*)さん :06/04/13 10:37
>>527
現行攻撃できないだけで全ての攻撃モーションキャンセルしてるよ
おかげで逆に遅くなってもいいからモーション表示させたいって要望があがるほど

Mob残骸なら弓手に頼めばすぐ作ってくれるから実験してみたいところだね

531(○口○*)さん :06/04/13 21:17
てことは、deadで攻撃中から待機に戻すようなプログラミングを
してると、拾えなかったときにずっと攻撃状態になることもありえる?

532(*○口○)さん :06/04/13 23:06
そもそも攻撃中から待機に戻す判定がdeadだけようなプログラミングを
普通しないから、ずっと攻撃状態になることはありえない

533(○口○*)さん :06/04/13 23:45
>>531
死亡判定のほかに、視界内にそのIDがあるかってのも判定にあるからそれで待機に戻る。
だから死亡即沸きだとそのmobが新品でタゲ移ってなくても攻撃してしまうわけでできればそれを避けたいね

534(○口○*)さん :06/04/13 23:56
共闘目的の一発殴るだけの戦法を組み込みたいのだけど
これはGetMyEnemyあたりで拾える敵を全部リスト化して順番に殴るようにすればいいのかな
敵の消滅と生成が順次行われていくからちょっと面倒そうだけど。
配布されてる中でこういうのを実装してるAIってないよね

535(○口○*)さん :06/04/14 00:20
共闘モードのフラグ作って、ONのときはATTACK_STへ行かずに
新しい状態関数作ってそこでリスト内の敵に1回ずつAttackコマンド撃ってけばいいんでない?
それでも結構ややこしい判定必要かもしれないけど。

536(○口○*)さん :06/04/14 01:16
こんな感じかなあ?もっとスマートにできそうな気がする
Attacked = {} -- 攻撃済みフラグ

1.
GetMyEnemy内でenemys に受ける攻撃対象となりうる敵のうち
Attacked[v] == nil (まだ攻撃していない)ならターゲットにする
攻撃対象となる敵がいるが、全て攻撃済みなら enemysのうち一番近い敵を攻撃(通常どおり)
Attacked で攻撃済みの敵IDがすでに存在しなければそのIDのフラグをクリアする。また、死亡オブジェクトでもクリアする。

2.
ATTACK_ST 内でAttack()後に
攻撃済みフラグをセット Attacked[MyEnemy] = 1 にして MyEnemy=0 にする

1に戻る

537(○口○*)さん :06/04/14 01:53
敵についてはヒストリー的管理をしているAI、見たことないですね・・・
わたしも以前考えかけて、ちと放置しています。

ちなみに、わたしのAIでは友人関連について「過去近くにいて、今は視界内にいない」
人をチェックして、10秒見失ったままならリストから外す、っていう処理を組み込んでいます。
#他ユーザのホムンクルスを友人管理するために入れた。
おんなじような手法で、敵に対しても対応可能かも。
すご〜く強引な記載ですが、なにかの参考になれば。

ttp://tomose.dynalias.net/RO/index.php?%A5%DB%A5%E0%A5%F3%A5%AF%A5%EB%A5%B9AI
friend.lua内、CheckTemporalyFriend()。これをAI()内から定期的に呼び出している。

538(○口○*)さん :06/04/14 01:54
>>536
画面外死亡を考慮しないとまずいだろうから、
Attacked[MyEnemy] = GetTick()
にして、死亡判定にくわえて殲滅想定時間外なら共闘を優先する
という感じがよさそう。

>攻撃済みフラグをセット Attacked[MyEnemy] = 1 にして
センスの話だけど、trueのほうが「じゃあ2だったらどうなるの?」とか
「nil/falseじゃなくて0が来るかも…」とか余計なことを考えなくてよさそう。

メモリ消費もboolのほうが少ないだろうけど…有意な差はなさそうだし
それはどうでもいいや。

539(○口○*)さん :06/04/14 01:57
>>537
「時間判定なら、死亡判定いらないんじゃないの?」と
同じようなこと考えたけど、それだと即湧きに対応できないんだ。

処理重くなるようなら、即沸きはイレギュラーとして
死亡判定を省略していいだろうけどね。

540(○口○*)さん :06/04/14 02:04
あ、あと根本的な問題として。
AI上でホムの攻撃はHitしたかどうかを判定することが出来ないから
共闘一発がMissだった場合はそのままになっちゃうけど
これは我慢するしかないかなぁ。

541(○口○*)さん :06/04/14 02:26
1発以上殴っちゃいけないわけじゃないし、少し長めにAttack送ればいいんじゃない?
スマートではないけどね。

542(○口○*)さん :06/04/14 02:28
ホムが二発目を繰り出す前に敵を殲滅するパァウワァーを!!!!
ケミの拳に宿すのだ!

543(○口○*)さん :06/04/14 03:38
>>538
GetMyEnemyの呼び出し毎にAttackedの攻撃済みIDを全部見て画面内にいる攻撃対象IDと比較、
画面内に存在しないIDは死亡と判断してIDから削除って感じにしようかなーと
時間だと>>539が言うように即沸きを殴らなくなってしまうからねえ
でもこれはこれで画面外に出て戻ってきたのをまた殴ってしまうけどそれは我慢か

>>540
Attackedに攻撃回数入れるとかして2,3回殴ってからMyEnemyをクリアってのは可能だけど
実際の命中は我慢するしかないねえ

544(○口○*)さん :06/04/14 09:48
今のところコマンドでオブジェクトIDが取れるのって
月光カプリスとAlt+右ダブルクリックだけ?

ミスしたら手動でちょんと突かせたいんだけど
Alt+右ダブルクリックってかなり面倒な操作なんだよね・・・
通常攻撃モード用に1個は残しておきたいし

なんでAlt+右クリックとかコマンド送らないんだろう?
ただのバグだったりして

545(○口○*)さん :06/04/14 10:39
>>540
忘れてたorz

mobdataと手入力した自Hitを見比べて、共闘率90%を目指す
というのはどうかな。

・少し足りないなら2発入れる(命中率69%で90.4%)
・かなり足りないなら、優先度を落として3〜4発入れる(55% 3発で90.9%、45% 4発で90.8%)
・絶望的なら無視するか、優先度最低で張り付く


…「n回攻撃をした」もはっきりしないんだった。ダメポ

・命中率90%〜100%ならAttack1回
・50%〜89%なら数ターンAttackを繰り返す
・それ以下ならなにもしない
こんな感じ?

546(○口○*)さん :06/04/14 10:46
>>543
即湧きってIDが一瞬(AI()が拾える範囲で)消えるんだっけ?

547(○口○*)さん :06/04/14 10:51
連続すまん。念のため「即湧き」の俺定義を。
「倒したmobが画面内にすぐ出てくること」

ボルト詠唱途中でmobが倒されたときに、画面内に湧いたmobに
そのままボルトが発動するような状況。

548(○口○*)さん :06/04/14 10:54
>>545
ホム以外タゲって居ないときは、ダメモーションを見るってのもいいかと。
攻撃間隔を2秒に1回とか、
1回Attackしたら離れて、敵がこっちに向かってくるかチェックとか。
確実性はやっぱりないけどね。

>>546
そんなに検証したわけじゃないけど、多分消えない。
AIで見る限りだと、位置がワープしただけに見えるはず。

549(○口○*)さん :06/04/14 12:05
>>548
ペースが速くなりがちなPT狩りでそんなに綿密にやると
共闘入れが追いつかなくなったりしないかな。
mobのタゲを奪っちゃったらその事後処理が大変そうだし。

あ、ということは共闘入れは「PTMが攻撃中のmob」を狙うように
したほうがお行儀良い?

>多分消えない
thx。
となると、このどれかだね。
・死亡判定+画面外リセット(出入りしたmobを誤認)
・死亡判定+時間判定(ピーキーで調整が手間かも)
・時間判定のみ
(比較的シンプルだけど即湧き対応が遅れる上、やっぱり調整が手間そう)
・画面外リセット(最もシンプルだけど、即湧き対応不可と出入りmobの誤認)

ふと思ったんだけど、画面外チェックを多用するとプロ露店のような
過密地帯では重くなりそう。

550(○口○*)さん :06/04/14 12:07
時間判定の方がよりシンプルな気もしてきた…。
頭の中で考えてるだけじゃだめだなぁ。あとでコード書いてみよう。

551(○口○*)さん :06/04/14 13:50
>>549
死亡判定の10万ルールを上手く使えば即沸き対応は出来るかも。
55000の奴を倒したら45000の死亡オブジェクトが出て55000の奴が画面内に沸く
ってことを考えると、
45000が出てるにも関わらず55000の奴が存在していたら即沸きなのでMyEnemy除外
みたいなこと出来るんじゃない?

55000が沸いた瞬間45000が消滅するんじゃなければ、だが。

552(○口○*)さん :06/04/14 15:08
>>551
そう思って第一・第二案には死亡判定を入れてあるんだけど、
>>539…というかぶっちゃけ「即湧きなんかに反応するために
普段無駄になりそうな処理を入れる必要はあるのか?」
ってことで端折ったケースも考えたんだ。

たぶん現実としては、処理の重さも大差ないだろうし
バグの温床にならないなら入れとけって感じだけども。

553(○口○*)さん :06/04/14 15:20
ぶっちゃけちゃうと、即沸き1匹ぐらい共闘取れなくてもいいじゃん
ってことになるから、ぶっちゃけ禁止!

554(○口○*)さん :06/04/14 15:28
>>553
即湧き対策って、横殴り対策じゃまいか?

555(○口○*)さん :06/04/14 15:51
>>554
横殴り対策だけなら、現在タゲの死体オブジェだけ見とけばいいんジャマイカ?
こんな感じに↓

if IsCorpse(MyEnemy) then MyEnemy = 0 end

function IsCorpse(id)
    local corpse = 100000 - id
    for i,v in ipairs(GetActors()) do
        if corpse == v then return true end
    end
    return false
end

556(○口○*)さん :06/04/14 16:02
このままだと死体消えるまでタゲれなくなるから、
死体オブジェ消えるまで、死体ID記録しとかないといけないけどな。

557(○口○*)さん :06/04/14 16:17
思いつきだけど、敵の探索の最初にこういうのを入れておいて
直前の生存mobと比較ってのはどうだろ。
local actors = {}
for i,v in ipairs(GetActors()) do
    if (IsMonster==1 and MOTION_DEAD~=GetV(V_MOTION,v) and not IsCorpse(v)) then
        actors[v] = v
    end
end
Actors = actors -- 現在の生存mob


function IsCorpse(id)
    for i,v in pairs(Actors) do
        if (id == 100000 - v) then
            return true
        end
    end
    return false
end

558(○口○*)さん :06/04/14 16:18
いかん、IsMonster(v)だった。

559(○口○*)さん :06/04/14 16:20
さらに蛇足だけど
>>555
GetActorsを毎回読み込むのはかなりの無理を強いることになるから多分キャッシュしたほうがいい

560(○口○*)さん :06/04/14 16:28
>>559
GetActors() のループ中に Actors 参照する方が問題あると思うぞ・・・。
うちのサンプルは AI() 中に1度通るだけの想定だから、その辺はあまり気にしてなかったり。

ついでに言うと、即沸き判定っていうことは、Mobの死亡状況が取れてないってことだから、
新規ターゲット時に弾くのは意味が無い気がする。

561(○口○*)さん :06/04/14 16:33
あぁ、Actors はキャッシュの意か。
よく理解せず返すのは失礼だったな、スマヌ。

562(○口○*)さん :06/04/14 17:38
即湧き対策=mob認知状態のリセット
横殴り対策もだし、共闘状態も。

共闘に関してはわざわざやらなくてもいいと思ったけど、
横殴り対策での判定を流用すればよかったのか。

>>560
>即沸き判定っていうことは、Mobの死亡状況が取れてないってこと
なんか食い違ってるっぽい。

即沸きを見分けるために死亡判定をする。
で、死亡判定=モーション判定+ID判定。
(ID判定があればモーション判定いらないかも)

563(○口○*)さん :06/04/14 18:08
>>562
漏れの文法がおかしいだけで、意味はそれだったり。

ただ、死亡判定にモーションはいらないかも。
攻撃してたIDと死体IDは別だし。

564(○口○*)さん :06/04/14 18:15
索敵時
・死亡モーションのIDを除外
・死体オブジェのIDを除外

死亡判定時
・対象IDが画面内に存在するかチェック
・対象IDの死体オブジェが出現したかチェック

こんな感じで・・・余計わかりにくいか・・・。
横道にそれてるし、暫くカキコ止めとこう・・・。

565(*○口○)さん :06/04/14 19:08
>>504
ミス修正しました^^;


ついでに10万ルール関連
ホムンクルス用ライブラリ :var.2006/04/14
HTDEAD.lua

標準AIに中の(例)のコードを貼り付けバッタで動作確認
※画面外から倒された敵、ターゲット指定スキル以外で倒された敵等未対策


OnATTACK_ST内部
  if (false == IsInAttackSight(MyID,MyEnemy)) then -- 敵が攻撃範囲外に出たら
    if (false == IsOutOfSight(GetV(V_OWNER,MyID), 100000-MyEnemy)) then -- 10万ルールIDが画面内に居れば
      MyEnemy = 0 -- ターゲットリセット
    else
      MyState = CHASE_ST
      MyDestX, MyDestY = GetV (V_POSITION,MyEnemy)
      Move (MyID,MyDestX,MyDestY)
      return
    end
  end

これでホムが攻撃している敵なら即沸き時、継続攻撃対策になるかと

566(○口○*)さん :06/04/14 20:18
>>565
それだと攻撃範囲ならやっぱり攻撃してしまうから
    if (true == IsOutOfSight(MyID,MyEnemy)) then    -- ENEMY_OUTSIGHT_IN
        MyState = IDLE_ST
        TraceAI ("ATTACK_ST -> IDLE_ST")
        return
    end
の後に
    if (false == IsOutOfSight(MyID,100000-MyEnemy)) then    -- ENEMY_REBORN_IN
        MyState = IDLE_ST
        TraceAI ("ATTACK_ST -> IDLE_ST")
        return
    end
とするだけでよいかも?
しかし死亡オブジェクトと即沸きのときに10万ルールの2種が同時に存在するのだろうか
即沸きは狙って起こせないからログで拾うのは困難だなあ

567(*○口○)さん :06/04/14 20:46
攻撃範囲内にも沸くの忘れてた^^; まぁ細かいところは言わなくても
どんどんアレンジしていく人ばかり集まってるだろうから適当に(ぇ

実体のmobは>>546-548の通り魔法詠唱が(WBも)繋がるから「即」沸きって
言われるんだし同時に存在しているはず(IDが変わるのも重複させない為かと

568(○口○*)さん :06/04/14 21:03
それ言ったら
死亡オブジェクトとがのこってるときに即沸きしたやつ殺したらどうなるの?
とか

まぁ、死体ぐらい消えても問題ないから上書きされて消滅するんだろうけど

569(○口○*)さん :06/04/15 02:48
流れ無視して質問。

TraceAI (GetV (V_HP,MyID))
TraceAI (GetV (V_MAXHP,MyID))
TraceAI (GetV (V_SP,MyID))
TraceAI (GetV (V_MAXSP,MyID))
TraceAI (GetV (V_HP,GetV(V_OWNER,MyID)))
TraceAI (GetV (V_MAXHP,GetV(V_OWNER,MyID)))

上からホムの現在のHP、MaxHP、現在のSP、MaxSP
ケミの現在のHP、MaxHPを取得して見たのですが、
ホムのMaxHP、MaxSP、ケミのMaxHPが上手く取得できません。
200〜300位の数値(リログしたりすると数値が変わる)になるのですが、
何か根本的な所で間違えているのでしょうか?
ちなみにデフォルトAIに付け加えて取得してました。

570(○口○*)さん :06/04/15 02:58
MyIDがちゃんと取れてる場所にあるかどうか、とか。
それぞれ単体で見ると正しく見えるしなぁ。

うちは少なくともそれでホムのHP、MHP、SP、MSPは取れてるっぽい。
一度変数に移してから使ってはいるけど。

571(○口○*)さん :06/04/15 03:43
更に流れを切って申し訳ない。

本人バニル使い。
4秒毎にSP回復するらしいので、もうちょっとでSP回復しそうなら不動明王化(゚д゚)
ってのをやってみました。
既に移動時に間隔置く機能は入れて、それ前提でやってます。

-- global variable
MoveTime = 0 -- 移動した時間
M_Interval = 400 -- 移動の間隔(ms)

SPRAfterMove = 4900 -- この時間まで次の移動を保留する(ms)
SPRBeforeMove = 2900 -- これ以上非移動時間があった場合、移動推奨時間(SPRAfterMove)まで待つ(ms)

function MoveInterval (id,x,y)

 local NowInterval = GetTick() - MoveTime
 if (NowInterval >= M_Interval) then
  local SPRTime = NowInterval - math.floor(NowInterval/4000)*4000
  if (SPRTime < SPRAfterMove - 4000 and NowInterval > 4000) then
   SPRTime = SPRTime + 4000
  end
  if (SPRTime > SPRBeforeMove and SPRTime < SPRAfterMove and GetV(V_MAXSP,MyID) - GetV(V_SP,MyID) > 0) then
   return
  end
  Move (id,x,y)
  MoveTime = GetTick()
 end

end

ここまで。

既存のMove () は当然ながらMoveInterval () を呼び出すよう変更入れてます。
ちょっとはSPが回復するようになったかな〜程度ですが、如何でしょうか。

572569 :06/04/15 05:30
require "./AI/USER_AI/Const.lua"
require "./AI/USER_AI/Util.lua"

function AI(myid)

  MyID = myid
   TraceAI (GetV (V_HP,MyID))
   TraceAI (GetV (V_MAXHP,MyID))
   TraceAI (GetV (V_SP,MyID))
   TraceAI (GetV (V_MAXSP,MyID))
   TraceAI (GetV (V_HP,GetV(V_OWNER,MyID)))
   TraceAI (GetV (V_MAXHP,GetV(V_OWNER,MyID)))
end

上記の文ではちゃんと全ての値を取得できますが、


require "./AI/USER_AI/Const.lua"
require "./AI/USER_AI/Util.lua"

function AI(myid)

  MyID = myid

-- TraceAI (GetV (V_HP,MyID))
   TraceAI (GetV (V_MAXHP,MyID))
-- TraceAI (GetV (V_SP,MyID))
   TraceAI (GetV (V_MAXSP,MyID))
-- TraceAI (GetV (V_HP,GetV(V_OWNER,MyID)))
   TraceAI (GetV (V_MAXHP,GetV(V_OWNER,MyID)))
end

の様にすると違う値が入るようです。
板汚しすみませんでした。

573むー ◆MxtFYKfdW6 :06/04/15 06:08
とりあえずorcsdun02.luaっていうOD2のマップデータ作ってみたんですがいる人いますかね?

574むー ◆MxtFYKfdW6 :06/04/15 06:27
あとはGD・プロ下水・ピラミッド・スフィンクス・伊豆D・FDのマップで
ホムで使いそうなマップがあればある程度なら作りますが。

575569 :06/04/15 07:03
と、思ったらどうも違うっぽい……
今572と同じ事をしてもどちらも取得できてない見たいです。
どなたか原因がわかる人いたらよろしくお願いします。

576(○口○*)さん :06/04/15 07:35
>>575
TraceAI(string.format("HOM MHP:%d",GetV(V_MAXHP,MyID)))
とかしてみたら?

577(*○口○)さん :06/04/15 08:45
>>574
畳1F

と言ってみる
カプリス&月光が壁越しに打てるかどうかも2とか入れれば良いかも知れない
他はやっぱり壁が薄くて壁越しに敵が見えやすいMAPかな・・・・
プロ水路3F、GD3F、PD1-2F&B2-3F、SD全層辺りが薄め
β2マップ以降だと時計、GH、おもちゃ、畳、アユタヤD辺りかな

ぶっちゃけ全MAP作ったとしてもパッチ変更等のチェックや対応が
出来る訳無いから主要MAPのみの作成が堅実かなとは思ってる
索敵範囲狭くすれば済んだりで需要が高くないからやりたいMAPからやっていけばいいかと

578むー ◆MxtFYKfdW6 :06/04/15 08:58
>>577
とりあえずOD2とSD2が完成。
自分のサイトないからアップできないorz
どこかアップできる場所教えてくだされ・・・

一応動作確認取れたらホムンクルス用ライブラリを配布するサイトのところに送ってみるつもりだけど。

579むー ◆MxtFYKfdW6 :06/04/15 09:02
畳マップは通行可能・不可のデータがないから今のところ作れないorz
あれば40分くらいで1データ作れるんですが。

580(○口○*)さん :06/04/15 10:53
>>575
取り合えず

TraceAI ("MyID : " .. MyID)
TraceAI ("V_HP : 8? = " .. V_HP)
TraceAI ("HP : " .. GetV (V_HP,MyID))
TraceAI ("V_AXMHP : 10? = " .. V_MAXHP)
TraceAI ("MHP : " .. GetV (V_MAXHP,MyID))
TraceAI ("V_SP : 9? = " .. V_SP)
TraceAI ("SP : " .. GetV (V_SP,MyID))
TraceAI ("V_MAXSP : 11? = " .. V_MAXSP)
TraceAI ("MSP : " .. GetV (V_MAXSP,MyID))
TraceAI ("V_OWNER : 0? = " .. V_OWNER)
TraceAI ("OwnerID : " .. GetV(V_OWNER,MyID))
TraceAI ("OHP : " .. GetV(V_HP,GetV(V_OWNER,MyID)))
TraceAI ("OMHP : " .. GetV(V_MAXHP,GetV(V_OWNER,MyID)))

これでおかしな値がないかチェック

少なくとも俺は↑できちんと出てるから

581(*○口○)さん :06/04/15 11:29
>>578,579
つ「MMOBBSアップローダー」「無料HPスペース」

つ「10MAPで1M超える」
つ「渡されても困る(責任もてない)」(本音)
in_sphinx1はzip圧縮すれば4kBちょっとになったけどそういう問題だけじゃないしお察しくださいとしか・・・
むしろ40分で1MAPやれるなら配布も作成もそちらにお任せします。(自分数時間掛かったしorz

>>575
TraceAIは連続で同じ文字列or数字が送られると2回目以降を無視するのを忘れてない?
HPもSPも全開だったら1回しか出力されないから取得出来ない様に見えるだけかと

582(○口○*)さん :06/04/15 12:35
ゼロマテリアルのどきどきAIを使っているんだけど
草を叩いてくれないのは不満。
本体が草を叩いたら一緒に草を叩いてほしいのに…

583(○口○*)さん :06/04/15 12:40
その部分のコードけずれば?
多分モンスターのタイプ指定して攻撃対象にしない if 文くんであるだけだから

584(○口○*)さん :06/04/15 12:53
うーん、どこをいじったらいいのか…

585(○口○*)さん :06/04/15 13:01
>>578
とりあえずsageて。ageるなってわけじゃないけど。

あと今どき「自分のサイトがない」とかただの泣き言でしょ。
無料サービスとかいくらでもあるのだから。

>>584
このスレだと>>583のような答えになる(悪い意味ではなく)から、
AI雑談スレに行ったほうがいいよ。

586むー ◆MxtFYKfdW6 :06/04/15 14:13
ttp://www5e.biglobe.ne.jp/~akemino/upload/mmobbs/files/3067.zip
OD2とSD2のマップデータです。

たぶんこれであってると思うけどよかったら誰か確認を。

587(○口○*)さん :06/04/15 17:22
>>572
trace吐くときにどれがどの数字か分からないから、単純に正常な値が
帰ってきてるのを見間違えてるだけな気がしてきた。


それ以前に、traceAIの引数は文字列だから、数値をそのまま渡すと
妙な事になるんじゃないかな、とかも思えてきた。

>>576 >>580 みたいに、求めた数値を書式付の文字列に変換して
ちゃんと出力してみるといいんじゃないかね。バディ。

588(○口○*)さん :06/04/15 17:24
って>>580見る限りは数値もそのまま出せるのか

589(○口○*)さん :06/04/15 17:24
GetTick()とかをTraceAIに突っ込むときはそのまんまでもよかったけど、
GetV関数とかで得る値を出力するときは>>580とかみたいにしないとダメだね。
引数を必要とする関数をダイレクトにやろうとすると失敗するのかな?

590(○口○*)さん :06/04/15 17:45
>>587-589
>581の
>TraceAIは連続で同じ文字列or数字が送られると2回目以降を無視するのを忘れてない?
これが理由じゃないの?

591(○口○*)さん :06/04/15 18:18
まぁ見出しつけてトレースすればわかるやね。
とりあえず質問主から反応あるまでこの話題は保留しとくか。

592(○口○*)さん :06/04/15 19:03
>583は若干間違い
ノンアクティブのAIでは
プレイヤーが攻撃したた敵を認識して攻撃しに行くという設定が無い

どきどきAIで草を殴らせたい場合は
「プレイヤーが攻撃したた敵を認識して攻撃しに行く」
を追加しないといけないってのが回答になる

593569=575 :06/04/15 20:07
レス遅れてすみません。

>>576の文で正確な値を取得できました。
が、今>>572を走らせると正確な値をちゃんと取得できるみたいです。
OS再起動したのが起因で正確な値を取得できるようになったのか
わかりませんが、板汚し本当にすみませんでした。

594(○口○*)さん :06/04/15 20:34
>TraceAIは連続で同じ文字列or数字が送られると2回目以降を無視
これを検証して欲しかったところだが…
正確な値を拾えたとき、HPSPは減っていたかい?

595(○口○*)さん :06/04/15 22:30
>>587
TraceAI は文字列しか受け取りませんが、Lua では数値と文字列は自動変換されます。
nil, table 等は変換されませんが、tostring() を使っておけば大丈夫でしょう。

TraceAI("v = " .. tostring(v))

596(○口○*)さん :06/04/15 22:58
>>595
ありがと。 nil帰ってくる可能性があるからその時に落ちてたのか。
とりあえずいつもstringをかましてはいるから大丈夫。

597(○口○*)さん :06/04/15 23:48
>>594
OK確認した
全快で>>569のコピペだと確かに2連続同じ値は出てない
その代わりGetVの値もきちんと取れてるから
特に問題なく暗黙の変換が作用してる

むしろ200〜300?の値ってのがよくわからないね
どこかにTraceAIで見落としてるのがあったのかな?

>>580の場合だと文字列連結子を使ってるからTraceAIに渡す前に文字列変換されてるね
別に数字だけでも出せるけど出来る限り項目名はつけましょうってことで。
値だけ出しても本当に出てるのがその項目なのかから調べんとならんw

598(○口○*)さん :06/04/15 23:59
200〜300はSPとかの値がずれ込んで表示されてただけでしょうな。
重複分を計算にいれなかったから。

599(○口○*)さん :06/04/16 02:29
・ソース
・結果のコピペ
・そのときの実際の状況

これがないんだから、外野が騒いでもしょうがない。

>>596
string.formatのことだと思うけど、その考えは甘いよ。
%dに数値・%sに文字列以外のものを渡すと、string.formatで
引数エラーになる。
自動変換があるから、%sに数値渡したり、%dに数値と見なせる文字列を
渡すのは許容されるけどね。

というわけでなにかエラー起きたら、とりあえずtostringしたもので
再挑戦してみるようstring.formatをラッピングしてみた。
書き下ろしでデバッグしてないけど。
do
 local _format = string.format
 function string.format(fs, ...)
  local st, ret
   st, ret = pcall(_format, fs, unpack(arg))
   if st then
    return ret
   end

   for i,v in ipairs(arg) do
    arg[i] = tostring(v)
   end
   return _format(fs, unpack(arg))
  end
 end
end

600(○口○*)さん :06/04/16 02:31
インデントミスった…。おかげでendも一個多い。orz

601569=575 :06/04/16 03:34
余計なレス増やしてすみません。
原因がわかったのでカキコ。
Const.luaの、V_MAXHP = 10 と V_MAXSP = 11の値が
V_MAXHP = 1 と V_MAXSP = 1 になっていたのが原因でした。
前にインデントの関係でタブ調整したときに
一緒に消してしまったのだと思います。
それで、インデント直してないファイルと直しているファイルを
AI.luaと一緒にUSER_AIにコピーしたかどうかによって
MAXHP と MAXSP に違いが出た様です。
(AI.luaだけコピーしていた時もあったので
正しいConst.luaの時は正しい値を返していたみたいです)
初歩的なミスでココまで話を大きくしてしまい、恥ずかしい限りです。

6021/2 :06/04/16 10:45
先行型を自力でタゲかぶりしないように
頑張ってみたんですがどうもうまくいきません

noenemyテーブル検索結果のt2が0みたいなので
テーブル格納がうまくいってないようなんですが
enemyテーブルのやつコピって作っただけなのに…

-------------------------------------------
-- 先攻型 GetMyEnemy
-------------------------------------------
function GetMyEnemyB (myid)
TraceAI ("GetMyEnemyB")
local result = 0
local owner = GetV (V_OWNER,myid)
local actors = GetActors ()
local enemys = {}
local noenemys = {}
local index = 1
local index2 = 1
local type
local target

603602 2/2 :06/04/16 10:48
for i,v in ipairs(actors) do
if (v ~= owner and v ~= myid) then
if (1 == IsMonster(v)) then
enemys[index] = v
index = index+1
else
TraceAI ("noenemys ADD")
target = GetV (V_TARGET,v)
noenemys[index2] = target
index2 = index2+1
end
end
end
local min_dis = 100
local dis
for i,v in ipairs(enemys) do
for t1,t2 in ipairs(noenemys) do
if (t2 == v) then
break
else
dis = GetDistance2 (myid,v)
if (dis < min_dis) then
result = v
min_dis = dis
end
end
end
end

return result
end

ご教授お願いします

604602 :06/04/16 10:51
ぐはっ、tabは認識されないんですねJaneDoe viewはorz

for i,v in ipairs(actors) do
if (v ~= owner and v ~= myid) then
if (1 == IsMonster(v)) then
enemys[index] = v
index = index+1
else
TraceAI ("noenemys ADD")
target = GetV (V_TARGET,v)
noenemys[index2] = target
index2 = index2+1
end
end
end
local min_dis = 100
local dis
for i,v in ipairs(enemys) do
for t1,t2 in ipairs(noenemys) do
if (t2 == v) then
break
else
dis = GetDistance2 (myid,v)
if (dis < min_dis) then
result = v
min_dis = dis
end
end
end
end

return result
end

ご教授お願いします

605602 :06/04/16 11:10
もうだめだほんと申し訳ないorz

606(○口○*)さん :06/04/16 11:16
>602
これだとnoenemysがいないとき(自分とホムと敵しかいないとき)は、
2重ループの内側に入らないからひっかからないな。

なおしかたはいろいろあるけど、
ちゃんと直すなら内側のループを関数化してnoenemysが空のときは
タゲ対象として判定結果を返すようにするのが後々楽そう。

てっとりばやくアルゴリズムを確認してみるなら
>if (v ~= owner and v ~= myid) then

if (v ~= owner) then
とする
必ず内側のループに入るようになる(自分は必ず取れるはずだから)が
直前まで自分が叩いていた敵、またはその即湧きがひっかからなくなるので
実用的ではないけどね。

607(○口○*)さん :06/04/16 11:48
がんばってるところすまんがコレそもそも無理
>target = GetV (V_TARGET,v)

主人、ホム、Mob以外のV_TARGETは-1が帰ってくる
noemnemysにはいるのはほかPCとNPCだからどんな状況でもnoenemysには-1が大量に入るだけ

Tabや半スペ認識しないのは2ch系BBSの仕様
使ってる2chブラウザは関係ないよ
DoeViewなら書き込む前にプレビュー見ればずれは確認できる

608(○口○*)さん :06/04/16 12:17
>607
そうでしょうか?
function AI(myid)
 fp = io.open("./AI/USER_AI/loglog.txt", "a+")
 local k = 0
 local ac = GetActors()
 for i,v in ipairs(ac) do
  if (IsMonster(v) ~= 1) then
   k = GetV(V_TARGET,v)
   if(nil == k) then
    fp:write(string.format("nil\n"))
   else
    fp:write(string.format("%s\n",tostring(k)))
   end
  end
 end
 fp:close()
end
これをプロ南で走らせた結果↓(0が多いのである程度端折り)
0
1152347
0
32797
33782
0
上がいっぱい並ぶ
ホムもマスターも接続してターゲットを指定していません
近くでPCにタゲるシャープシューティングやらヒールやらをしているキャラが居ましたので
そのターゲットが入っているんだと思いますが?

609(○口○*)さん :06/04/16 12:41
貼り付けるソースのインデント(字下げ)は
半角空白を入れるなら半角で「&nbsp;」と入れると半角空白「 」が表示される
全角空白を入れるならそのまま「 」でいい
例)
if x == 1 then
    TraceAI("1") -- 半角空白4つ
elseif x == 2 then
  TraceAI("2") -- 全角空白2つ
end
全角の場合はコピーしてそのまま使えないので注意

なんかこういう感じのテンプレに入れたほうがよくないかな

610(○口○*)さん :06/04/16 12:55
ちょっとわかりにくいのだけどnoenemysってどういう意図の変数なのかな
敵候補のIDと比較してるけど「他人が狙ってる敵は除外する」って意味であってる?

それだと一番多く入るであろう0と−1ははじかないとわけわからないと思うんだ
target = GetV (V_TARGET,v)
if (1 == IsMonster(v)) then
    enemys[index] = v
    index = index+1
elseif (target >= 0) then
    TraceAI ("noenemys ADD")
    noenemys[index2] = target
    index2 = index2+1
end
どうせやるならIDとHOMUNTYPE見てプレイヤーとホムだけピックアップしてから比較したほうがいいと思うけど。

611602 :06/04/16 13:14
>>606-610

お返事ありがとうございます

スクリプトいじってたんですが
変なとこさわったのか実行時にエラーにorz

ちょっと自宅PCが使えなくなるので
これから漫画喫茶へ移動してじっくりいじってみます

また向こうで書き込ませてもらいます

>>610

書かれているとおりです
横殴りしないようにかつ非アクティブの敵を叩くように
自力でできないかなと…

612(○口○*)さん :06/04/16 14:26
mobdata.luaのサイト
MAP[x][y] -- 座標[x,y]が進入可能セルかどうか yes -> 1 no -> 0
てxとy逆だと思うお
個人的にはピラ地下1のマップ欲しいな…

613(*○口○)さん :06/04/16 14:48
( ゚Д゚)==>>612
(゚Д゚)
_|~|O<CheckCell (x,y) -- 座標[x,y]が進入可能セルかどうか yes -> 1 no -> 0:var.2006/04/16

ピラ地下1ってシーフギルドだった様な・・・
moc_pryd05=ピラミッドダンジョン B2Fかな

614騎士子さん :06/04/16 16:35
某所からの誘導でお邪魔いたします

某りくえすとでmapでーたを作成してみたのですが
mobdata.luaの中の人のmapでーたと若干の相違があるので(y軸ズレ)
RO内でご確認できる方はよろしくお願い致しまする

ただ関数化していない、データの意味合いが違うのでそのあたりは
手直ししてください

0:移動可能セル
1:移動不可セル
5:移動不可、遠距離攻撃可能セル

ttp://sakage.main.jp/ro/mapbb/
で生成してる画像の出力先をちょこっと弄っただけなので
視覚的に検証される場合にはご利用下さいませ


mobdata.luaの中の人のへ
乙でs。
別件になりますがchar_table.iniのでーた参考にして頂けたみたいで゚:。£ονё゚:。
むしろ適当ですみません・・・
そして今回は逆にmobdata.luaのでーた参考にさせて更新させてもらいましたヾ(*'ω'*)ノ
char_table.iniもにはDB各データ持ってはいるんですが、ぜんぜんメンテしてないんですよね・・・

615(○口○*)さん :06/04/16 16:42
肝心なもの張り忘れた(゚д゚)
http://sakage.main.jp/ro/mapbb/lua/in_sphinx1.lua

616むー ◆MxtFYKfdW6 :06/04/16 16:51
>>613
ピラ地下2ってことは牛マップですかね。
今から作ってみるので1時間以内にできると思います。

とりあえず前にアップしたOD2とSD2は
/whereで出る座標で7,293の場所だと
MAP[293]の左から7つめという感じに変換してますがこれであってますかね?

617(○口○*)さん :06/04/16 16:57
>>614
まぷーびーびーの画像データからluaデータ生成しようとか
構想してたら、中の人にもっと効率いいことやられた(゚д゚)

618むー ◆MxtFYKfdW6 :06/04/16 17:08
ttp://www5e.biglobe.ne.jp/~akemino/upload/mmobbs/files/3070.zip
ピラ地下2ここまで完成。
あとはY軸の数字入れて必要な記述書けば完成です。

619むー ◆MxtFYKfdW6 :06/04/16 17:11
今から実際に行ってみて座標あわせしてきます

620(○口○*)さん :06/04/16 17:13
便乗リクエストで申し訳ありません
黒蛇MAPもあったらいいな・・なんて
ソグラト砂漠 13 (moc_fild13)ですが検討よろしくです

621むー ◆MxtFYKfdW6 :06/04/16 17:16
>>620
http://ro.deny.jp/images/map/moc_fild13.gif
でおっけですか?

ピラ地下2完成したら作ってみます。
(この後忙しくなるので夜中とかになりそうですが)

622(○口○*)さん :06/04/16 17:18
即レスいただいた!ありがとうございます(TдT) 

623むー ◆MxtFYKfdW6 :06/04/16 17:22
ピラ地下に座標確認にいったらスタンして死んだorz

624(○口○*)さん :06/04/16 17:32
>>617
でへ。といっても現在ROやってないのでいろんな意味で微妙です(´・ω・`)/~~

MAP的には全MAPできてる(というか自動生成なので)んですが
もちっと仕様を理解してからにしようと思います。
配列0,0開始じゃなくていいの?とか

625むー ◆MxtFYKfdW6 :06/04/16 17:57
ttp://www5e.biglobe.ne.jp/~akemino/upload/mmobbs/files/3071.zip
ぴら地下2完成ですよーっと

626むー ◆MxtFYKfdW6 :06/04/16 18:01
完成まで約1時間ですね。

とりあえず
最初の
function CheckCell (x,y)
return MAP[y][x]
end

--------------------------------------------------

MAP={}
MAP.default = {〜
の部分が変更になったときはそれを最新のに書き換えればOKなはずです。
あとのマップデータには変更ないですし(仕様が変わったら直さないとですが;)

627(○口○*)さん :06/04/16 18:41
>>624
例えば z = x + y (x,y: 0〜2)を配列で求める場合
table = {}
table[0] = {[0]=0,1,2}
table[1] = {[0]=1,2,3}
table[2] = {[0]=2,3,4}
z = table[y][x]

[0]=0 というのは「[0]を初期値にする」という意味はなく、
添え字省略したものは全て[1]から詰められてゆくことに注意。

data[0] = {[0]=0,1,2}
data[0] = {1,[0]=0,2} --同じ

これはluaの「配列」の定義外になってしまう(配列として処理すると
[0]を無視する)けれども、ループ回すような処理に使うことはないので
大丈夫でしょう。

でも(0,y)や(x,0)に進入できるマップは通常無いはずだから、未定義で十分かも。
アクセスするほうが悪いってことでw

あとスレ違いだからと迷ったけど、やっぱ言っちゃう。
わりと最近に騎士を初めたのでまぴーびーびーが大変役立っています。多謝。

628(○口○*)さん :06/04/16 19:33
>607,608
608とにたようなコードで試してみた、
今のバージョンだと狩り場ではGetV(V_TARGET,v)がちゃんととれるっぽい。
Pv,Gvはいかんのでわからん (・∀・)

629602 結果(1/3) :06/04/16 20:11
遅くなりましたが報告を
無事完成しましたありがとうございました^^
もっと簡単な方法があるのかもしれませんが
今の自分ではこれが精一杯
精進します

for i,v in ipairs(actors) do
   if (v ~= owner and v ~= myid) then
       target = GetV (V_TARGET,v)
       if (1 == IsMonster(v)) then
           enemys[index] = v
           index = index+1
       elseif (target >= 0) then
           noenemys[index2] = target
           index2 = index2+1
       end
   end
end

630602 結果(3/2) :06/04/16 20:15
local min_dis = 100
local dis
for i,v in ipairs(enemys) do
   local enemy = ENEMY_JUDGEMENT (myid,v,noenemys)
   if (enemy == 1) then
      dis = GetDistance2 (myid,v)
      if (dis < min_dis) then
         result = v
         min_dis = dis
      end
   end
end

631602 結果(3/3) :06/04/16 20:21
function ENEMY_JUDGEMENT (h,m,t)
   local owner = GetV (V_OWNER,h)
   local dis = GetDistance2 (owner,m)
   if (dis > 3) then  -- ケミから遠い場合敵としない
      return 0
   end
   if (t == nil) then --テーブルが空のとき
      return 1
   end
   for i,v in ipairs(t) do
      if (m == v) then
         return 0
      end
   end
   return 1
end

友人に検証つきあってもらったんですが
画面外から敵をつれてきた場合(enemys,noenemeyテーブル作成後)は
殴りに行ってしまうんですがまあ仕方がないとあきらめます( ´・ω・`)

632(○口○*)さん :06/04/16 20:30
>>629
elseif (target >= 0) then

elseif (target > 0) then
でいいんじゃない?
ロックオンしてないV_TARGETの値 0 までリストに代入する必要性がないよ。

>>631
ENEMY_JUDGEMENT の返り値が真偽値なら 0 と 1 でなく false と true にしたほうがよくないだろうか。
こうすれば >>630
for i,v in ipairs(enemys) do
    if (ENEMY_JUDGEMENT (myid,v,noenemys)) then
        dis = GetDistance2 (myid,v)
        if (dis &amp;lt; min_dis) then
            result = v
            min_dis = dis
        end
    end
end
と書ける。
別に false/true じゃなくても if (ENEMY_JUDGEMENT (myid,v,noenemys) == 1) then にできるし
他で流用しないならenemyに代入する必要がない

633(*○口○)さん :06/04/17 00:19
ども、mobdata.luaの中の人こと姫野みことです

>>614,624
えと、ROのクライアント上?データだと座標0,0までデータが存在していますが、
Luaの配列定義の一般型が>>627でも言われている通り
Luaの配列Array[n]はn=0,1,2,3...ではなくn=1,2,3,4...になっています。
なのでin_sphinx1のMAPで見て左下の侵入可能限界座標[ 6 , 6 ](/where結果)から
例のy軸ズレ(実際はx軸もズレていますが^^;)はLua配列とROクライアント座標を補正した結果になります。

また補正は配列に直接施さず、参照用関数を
function CheckCell (x,y)
return MAP[y-1][x-1]
end
としても問題ありません。

一応、NULL(nil)配列の要素を参照するとLuaがエラーを吐くのでMAP.defaultで一軸方向のみ対策をしていますが
function CheckCell (x,y)
if MAP[y-1] and MAP[y-1][x-1] then --未定義なら判定が偽
return MAP[y-1][x-1]
else
return 0
end
end
とした方がより堅牢です^^;
※Array[1]〜[4]まで定義されている時に未定義のArray[5]は参照出来ますが、
Array[5][5]を参照した時にエラー(クライアント停止)が出るということです。


>別件になりますがchar_table.iniのでーた参考にして頂けたみたいで゚:。£ονё゚:。
バレタ!Σ(0w0(違
割とRO内で動くことが少なくて実際に調査に行けないので凄く参考になってます。

>そして今回は逆にmobdata.luaのでーた参考にさせて更新させてもらいましたヾ(*'ω'*)ノ
( Д)゚ ゚
細かい所でミスがポロポロ出てきたりするデータで申し訳ないです_|\ ((○

バイナリデータを扱うのが苦手で手を付けた割にろくな物も作れず手を引くのか・・・と
半ば諦めていましたが、MAPデータの方は生成画像から出力出来る様なので一安心?です。
データ形式等は割りと作ったもん勝ちなので扱いやすい形式でOKだとおもいます

634(○口○*)さん :06/04/17 00:35
そんな名前だったのか

635(○口○*)さん :06/04/17 01:05
>>633
>MAP.defaultで一軸方向のみ対策をしています

MAP = setmetatable({}, {__index = function(self) return self.default end})
MAP.default = {(略)}

default単体では意味を持たない、はず。

636(○口○*)さん :06/04/17 01:12
>>627
参考になりますヾ(*'ω'*)ノ
ガーターは433氏始めとする当時のスレ住人の賜物ですぬ

>>633
luaとAIの仕様を厠でざっと読んでみまして、なるほど配列1始まりなのかと
return MAP[y-1][x-1] で書いてるとこでした:)
が、無効な座標渡された場合のエーラ考えると後者の方が良いっぽいですね
参考になりますです

で、データ形式なんですが0,1,5の意味はRO本体が使用している形をそのまま使うと
前述の、0:移動可能セル、1:移動不可セル、5:移動不可、遠距離攻撃可能セル
な感じになるのですが、既に利用されてる方がいらっしゃるので
とりあえず現状にあわせて

0:移動不可
1:移動可能

で作ってみようと思います
遠距離攻撃系が実装された場合には「移動不可、遠距離攻撃可能セル」の
判定が必要になってくると思うので、その時に再考すればいいかな、と

あとAIまにゅあるをざっとしか読んでないんですが、思った以上に
提供関数少ないんですね
現在MAPデータの動的提供できるかなと思ってたんですが、
どうにもMAPID返してくれそうな関数がみあたらない・・・

こちらもROでなかなか動けないというか、むしろ引退してもうたので
なかなか微妙な感じではありますが、ホムは面白そうなので
ちょっとかじってみようと思いまする

637(○口○*)さん :06/04/17 01:29
MAP.default = setmetatable({}, {__index = function() return 0 end})
こっちもこれでよかった。

でもこの方法でx軸の範囲外を0で埋めるようにするのはめんどくさいし、
そうなるとやっぱ>>633のようにアクセス用の関数で処理した方がいいような。

もしくは0を全部falseにして、
false:壁
nil :MAP外(データ未定義)
としたほうが、このへんはスムーズに処理できる気がする。

MAP = setmetatable({}, {__index = function(self) return self.default end})
MAP.default = {}
MAP[1] = {1,false}
MAP[2] = {1,false}

if not MAP[y][x] then
 -- 進入不可の場合
end

どう見ても>>633(アクセス関数を用意する)のほうが親切です。
本当にありがとうございました。

638(*○口○)さん :06/04/17 01:45
>>635
確かにdefaultだけだと意味が無かったですorz
x,y両方対応できる if MAP[y] and MAP[y][x] then がよさそうですね

>>636
座標は取得できてもMAPIDが取得できないのが痛いところですね
WP座標を2等に設定しAIがリロードされた時に、隣接MAPへの移動を検知するのは考えたんですが、
ポタやらカプラ移動、安息でも簡単に現在地を見失ってしまうのでなかなか^^;
自分はリーフが最初だったのでまだ確認はしていませんが、鳥とゼリーに
遠距離スキルが各1種あるので遠距離攻撃可能セルはあった方がいいかもしれません

639(*○口○)さん :06/04/17 01:50
追記
関数でエラー対策をする場合、値が0しかない行と
行末の0は削除してしまうのがよさそうです

640(○口○*)さん :06/04/17 02:25
とりあえず何も考えずに書いたらこんな感じになってしまいました

function GetMapSizeX()
return MapSizeX
end

function GetMapSizeY()
return MapSizeY
end

function CheckCell (x,y)
if x < 0 or y < 0 or x > MapSizeX - 1 or y > MapSizeY - 1 then
-- Map範囲外
return nil
elseif MAP[y+1] and MAP[y+1][x+1] then
-- データ発見
return MAP[y+1][x+1]
else
-- データ未発見
return nil
end
end

MapSizeX=300
MapSizeY=300
MAP={}
MAP[300]={ (略) }
 ・
 ・
MAP[1]={ (略) }

上記はin_sphinx1の場合ですが、MAPは300*300Cellで構成されていて
RO上ので座標は0〜299,0〜299になります。
配列格納時には各1〜300の添字で格納し、あくせっさは(x,y)のRO座標を引数にして
移動可能セル(1)か否(0)か、または無効な引数か(nil)を結果として返しまする

が、移動不可マスと未定義を同義に扱えばデータ圧縮できるなあ・・・とも思いますね
(ALL壁のY軸配列は定義しない、X軸以降ALL壁のデータは定義しない)
うーむ・・なやむる

641(○口○*)さん :06/04/17 02:25
あと遠距離攻撃の崖撃ちを使用するAIがあるなら、移動不可&遠距離攻撃可能セルも
定義した方がよさげですが、対象Mobとの位置関係をうまく計算できないと生きないっぽ

lua歴2時間なのでもちっと悩んでみまする

642(*○口○)さん :06/04/17 03:51
--定数
MAP_ENABLED = 0 -- 移動可能
MAP_DISABLED = 1 -- 移動不可
MAP_LONGRANGE = 5 -- 遠距離攻撃可能

--関数
function CheckCell (x,y)
〜略〜

といった風に定数として用意しておけば割と事後の置き換えは楽になります。

ファイル容量を削るだけなら1100 0011 >> C3 としてCheckCellで要求部分のみデコードしてやるのも手です。

643(○口○*)さん :06/04/17 05:39
久々にのぞいたら移動不可セルの認識が現実的になってきている
Σ(゜Д゜=;゜д゜)

他力本願になっていますが、プログラムは触った程度の技術しかない自分には
AIスレの人の開発がものすごい助かっています

今回のはやってることが難しそうでコードの理解に時間がかかりそう…

マイナーな配布AIの作成者ですが、皆様の開発結果をいつも参考にさせて頂いています
がんばってください
そして無力な自分に少し凹む
||||orz

644(○口○*)さん :06/04/17 08:41
Map定義をどんどん進めてくださっている方がいるので、
これに関連した別の課題についてのネタ振り&情報提供しておきます。

以前から挙がっているMove()系の話題で、
「標準のMove()は、目標地点までの多少の障害物があっても迂回して移動してくれる」
という話がありました。
今回Map情報で「目標地点までの直線経路に障害物アリ」というのは判断できるようになったとしても、
それを鵜呑みにする必要はない(Move実行すれば実は行けてしまう)ケースもある、ということです。

そこで、障害物を迂回して移動できるMove()拡張を試作して見ました。
まだ試作段階&LUAの配列を扱うのになれていないので少々強引につくったコードですが、
なにかの参考になれば、という感じです。
ttp://tomose.dynalias.net/RO/index.php?plugin=attach&pcmd=open&file=Movelib.lua&refer=%A5%DB%A5%E0%A5%F3%A5%AF%A5%EB%A5%B9AI
(上記ファイルへの直リンクなので、心配な方は
 ttp://tomose.dynalias.net/RO/index.php?%A5%DB%A5%E0%A5%F3%A5%AF%A5%EB%A5%B9AI の一番下、
 添付してある Movelib.lua を参照のこと)

上記内、 MoveEx() 以下いくつかの関数群がそれ。
最初にMoveEx()を呼び出すと、現在位置から目標地点までの障害物有無を確認、
何か障害物がありそうならば迂回ルートを検索して複数の直線的Moveに分割。
以後、同じ到着地点へのMoveを定期的に(例えばOnMOVE_CMDなどから)呼び出すことで、
「まだ移動中/最終地点まで到達成功/移動できない」といった情報が戻ります。

ルート検索アルゴはいわゆる迷路検索用として知られているものなので、
単純な障害物だけでなく、かなり複雑な迷路状のものも突破できるはずです。
まあ、現状のROではそこまでは不要だと思うので、オーバースペック」だとは思いますけど。

645(○口○*)さん :06/04/17 10:58
これで更にワープポータルの位置とかカプラとかの動かないNPCの位置とかを入れたらMAP自動判別できないかしら?

646(○口○*)さん :06/04/17 11:26
lualuaすると言いつつ風の大地を開いてしまいました
午前半休でもいいですよねっ、宇賀神さん・・・リリー・・・

>>642
(・∀・)!!

>>644
うわあー、すごくいいー、MAP定義いらねー

>>645
さっきうんkしながら妄想してたんですが、全MAP定義を
なめなめして差異を判定すれば比較的簡単にできる事に気付きました

全部ちぇきするのはナンセンス極まりないので、チェックするポイントを
ぴっくあっぷするロジックを書いて、でーた化しなきゃいけませぬが

647644 :06/04/17 11:32
ID違いますが644です。

>>646
いいえ、あくまで「Map定義があって進入不能セルがわかっていて」初めて使えるアルゴです(^^;
そういう意味でも、Map定義してくれる方に感謝。

#いえ、644内にも「自力でMap調査する仕組み」は入っているのですが、
#実際にROのマップ全てを歩いてまわるとすご〜〜〜く時間がかかるので (^^;;;

648(○口○*)さん :06/04/17 11:33
嘘です。顔洗いながら考えてみたら、根本的に無理でした
ごめんなさいっ!

649(○口○*)さん :06/04/17 11:40
>>647
∠´×`)
目を通させて頂いたんですが、迷路検索面白いです
これ学生の課題に出てきそうだなーとか思いました

>>648はMAP自動判別の件でs
ホムに可也不審な動きをさせればおkですが、
それでも全てに対応できるわけではないので非現実的・・・ぽい

650(○口○*)さん :06/04/17 12:23
連投すみませぬ

とりあえず全MAP流してみました
ttp://sakage.main.jp/ro/mapbb/lua/maplua.zip
1.9Mになってしまいましたpgr

現状はこんな↓感じです
ttp://sakage.main.jp/ro/mapbb/lua/in_sphinx1.lua
データの圧縮、関数の仕様についてはおいおい
というかむしろ適任な方がいっぱいいらっしゃるので以下略

Map名拾うの、はしょってるのと、現在のFile名は実はMAPIDじゃなくて
MAPのイメージ名になってますのでそのあたりはぼちぼち直します
MAPIDとMAP名、イメージ名の関係はとりあえず↓にて
ttp://sakage.main.jp/ro/mapbb/romaps.html

手抜きだらけですが、遅刻しそうなので逝ってきます(`A')

651むー ◆MxtFYKfdW6 :06/04/17 13:08
おおぅΣ(=д= ノ)ノ

これでマップデータを使った何かができるようになりますね。
AIフォルダに直接つっこむと邪魔になるのでMAPフォルダ作ってそこにいれれば楽ですね。

652(○口○*)さん :06/04/17 13:13
>>642
Luaは16進数もビット演算も扱えない…。

table["C3"] = {1,1,0,0,0,0,1,1}
とかやるはめに。

>>644
>MoveEx()
後で読む(ごめんなさいっ

>do -- Begin of "FollowtoOwner" library block.
なんとなく気になったんだけど、これはfunction外でlocalや
local functionを使わないならいらないかなぁ。
使うときのために、テンプレートとして仕込んでるとか?

あといちおう。
ファイル自体が一つのblockなので、末尾にreturn書けるし
トップレベルでのlocalはファイル限定(呼び出し側に漏れない)の
スコープを持つ。

>>649
たぶん自動判別最大の問題は、せっかく分単位のオーダーで自動判別をしても

「ハエすると忘れる」

ファイルに書き出して永続化すると、今度は忘れなさすぎて
どのタイミングで再調査を始めればよいのかが悩み。


ところで「移動できたか」は、GetV(V_MOTION,myid)がMOTION_MOVE
ではなくなったときに指定座標にいるか、でできないかな。
そもそも自分のモーションを取れたか忘れたけども。

653(○口○*)さん :06/04/17 13:16
文字列使う必要ないよ。orz
table[195] = {1,1,0,0,0,0,1,1}

でも直観的にわかりにくい…。

654(○口○*)さん :06/04/17 13:24
マップ移動直後のワープポイント座標からマップを特定しても
マップ移動後の蘇生やコールホムでも簡単に誤認してしまうのだよね。
ログインやカプラ転送もあるから出現先が必ずしもワープポイントとは限らないし。
特定エリアに限定すればかなり面白い課題だ

655644 :06/04/17 13:26
>>652
いろいろご指摘、どうもです(^^

おっしゃるとおり、do 〜〜のブロック記載はあとでソース整理する際にわかりやすくするためのメモみたいなものです。
上記の形でブロック内に切っているものは(外部から呼ばれるのが前提のMoveEx()以外は)
外部から見えなくても問題ないはずなので。
ただ、恥ずかしながら「LUA は専門で無いため、細かい作法を理解しきっていない」というところもあります。
なので、ご指摘いただけてうれしかったです (^^

656(*○口○)さん :06/04/17 14:37
JavaScriptで使っているコードなんですが
kc=',';
function deco4(x){//2桁の16進文字を2進に(間にカンマ入り)
  return deco3(deco(x.charAt(0)))+kc+deco3(deco(x.charAt(1)));
}

function deco3(x){//10進を2進に(間にカンマ入り)
  n=Math.floor(x/4);
  m=x%4;
  x1=Math.floor(n/2);
  x2=n%2;
  x3=Math.floor(m/2);
  x4=m%2;

  return x1+kc+x2+kc+x3+kc+x4;
}

function deco2(x){//2桁の16進文字を10進に
  return deco(x.charAt(0))*16+deco(x.charAt(1));
}

function deco(x){//16進文字を10進に
  return "0123456789ABCDEF".indexOf(x);
}


ココからLuaの話
string.findとstring.subまたはstring.byteで上記の様な操作をすれば
"C3">"1,1,0,0,0,0,1,1"が生成できます。
table[3] = {0,0,1,1} table["C"] = {1,1,0,0}を用意して
MAP[159]={"C",3,....}でも十分可能です。
MAP[123]=[[3FFC.......]]としてstringで必要部分を抜き出すのが理想かな

657(○口○*)さん :06/04/17 16:55
>>654
AI.lua初期化時点で近くにWPがある場合は「MAP移動を挟んだもの」と
みなして、自分の出現座標とWPの座標からMAP特定できるかも。
どこまでの精度が出るかは、調査してみないとわからないけど。

というかもしかして、WPのIDからMAPわかったりしない?

>>655
>メモみたいなもの
納得。ありがとう。

>>656
大切なのはできるかできないかじゃなくて、関数用意してまでムリに
16進数表記にする必要があるのかということ。
通信があるなら削る必要もあるけど、メモリやファイルサイズに
余裕がないわけでもないし。
なによりここいらの部分でバグ出したら泣きそう。

とはいえ、そういうのを考えるのは楽しいけどね。
>"0123456789ABCDEF".indexOf(x);
素直に「なるほど」と思ったし。

あとどっかの言語オタクが言ってるけど、名前重要。
テキトーな命名をするからコメントが必要になるんだ。
デコデコ言ってるからROニメ思い出しちゃったじゃないか。

658(○口○*)さん :06/04/17 16:55
lua版ついでに桁不問。

function dec2bin(i)
 if i == 0 then
  return "0"
 elseif i < 0 then
  return
 end

 local bin = ""
 while i > 0 do
  bin = math.mod(i, 2) .. bin
  i = math.floor(i/2)
 end
 return bin
end

function hex2dec(s)
 local dec = 0
 s = string.lower(s)
 for i = 1, string.len(s), 1 do
 local pos = string.find("0123456789abcdef", string.sub(s,i,i), 1, true)
  dec = dec * 16 + pos - 1
 end
 return dec
end

function hex2bin(s)
 return dec2bin(hex2dec(s))
end

659(○口○*)さん :06/04/17 17:11
やっぱhex2decはテーブル使った方がすっきりするかもしれない。
do
local hex_table = {
["0"] = 0, ["1"] = 1, ["2"] = 2, ["3"] = 3, ["4"] = 4,
["5"] = 5, ["6"] = 6, ["7"] = 7, ["8"] = 8, ["9"] = 9,
a = 10, b = 11, c = 12, d = 13, e = 14, f = 15
}
function hex2dec(s)
local dec = 0
s = string.lower(s)
for i = 1, string.len(s), 1 do
dec = dec * 16 + hex_table[string.sub(s,i,i)]
end
return dec
end
end

660(○口○*)さん :06/04/17 17:50
MoveEx()読み途中だけど。

>MoveEx_TargetX = 0
同じ変数の初期化を何カ所かで行ってるから、
local MoveEx_TargetX = 0
のミスじゃないかな。

Luaはグローバル変数がデフォルトだから、
>外部から見えなくても問題ないはず
というよりは「見えないようにしたいのに見えちゃってる」だと思う。

特にworkmapとかはMoveExとその下請け関数の間でかなり密接に
共有してるから、スコープを狭くしたほうがよさそう。

あとコメントがMoveEx()で中身がMoveExold()だったりするのは
作る過程の産物だろうけど、こういうことをすると楽かも。
local function MoveExA() end
local function MoveExB() end
local function MoveExC() end
MoveEx = MoveExC -- MoveExCにMoveExという別名をつけて公開

>Rout
Route(゚∀゚)

で、なんでコードレビューみたいなことばっかりやってるんだろ。orz

661(*○口○)さん :06/04/17 20:10
function CheckCell (x,y)
  local n = math.ceil((x+1)/4)
  if MAP[y+1] and n <= string.len(MAP[y+1]) then
    return reader (n,x,y)
  else
    return 0
  end
end

function reader (n,x,y)
  local m = deco2(deco(string.sub(MAP[y+1],n,n)))
  return m[(x-4*n+5)]
end

function deco2(x) -- 10 -> 2
  local n=math.floor(x/4)
  local m=x-n*4
  local a=math.floor(n/2)
  local b=n-a*2
  local c=math.floor(m/2)
  local d=m-c*2
  return {a,b,c,d}
end

function deco (x) -- 16 -> 10
  return string.find('0123456789ABCDEF',x) - 1
end


MAP={}
MAP[199]="03FCFF3FFFF3FFFFFFFFFFFFFFFFFFF3FCFFFFFFFFFCFF3F"
--略--
かなりいい加減に言えば「0,0,0,0,」が「0」に減るからデータ部分が約1/8
CheckCellの応答速度は遅くはなるけど容量対効果はまだ未知数

662(*○口○)さん :06/04/17 20:10
>>657
16進表記にする必要は全く無い、単に既に作ってある関数が流用できるからって言う底の浅い理由だけ
ただ、容量を削る必要性はかなり高い>>650でファイルサイズが1.9Mって言ってる通り
解凍すると約70MBって洒落にならん容量になる(デスクトップに開いて・・・orz
通常、狩り活動するであろうMAPは大雑把に100kB、200kB、300kBが1/3ずつって感じ

容量的には完全にバイナリファイルにして、現在いるMAPのみをioから開いて
Lua形式に変換してメモリに読み込ませるのがいいんだけど
既にぶっちゃけてるけどバイナリ嫌いだからスルー、間取って16進にした訳
それと現状・・・というか656の時点で考えてるのはCheckCell時に必要なポイントだけ
読み出すことだから1文字に限定して作っちゃってOK

コメント云々は趣味とかも混ざるだろうけど「indexOf(x)」とかJavaScript仕様が
Lua人に分からないだろうと思ってやっつけで関数がやってる事を付けただけ(ノ∀`)

663(*○口○)さん :06/04/17 20:24
追記
遠距離攻撃可能セルの情報が入らないから事実上需要は自分くらいかもorz
そしてふと気づいたらIDがDQN・・・・・意味は調べてから知った・・・
カレー食うか

664(○口○*)さん :06/04/17 20:26
どうせ使うマップはそんなに多いわけじゃないし
一度にrequireするのは1ファイルだけとするならまあなんとかなるかな。
データの圧縮も大事だけど、展開とアクセスの早さも大事。
16進数では扱うのが難しくなってしまうから生データとしてはあのままでいいと思う。

しかしテキストとはいえzip圧縮ってこんなに小さくなるんだな。びっくりだ。

665(○口○*)さん :06/04/17 20:29
exec使えるならluaで変換するよりmapulua.zipから必要なのだけ展開して読み込ませたりできないだろーか。
zipだめならcabとかならWIN標準で展開できたはずだし

666(○口○*)さん :06/04/17 21:59
仕事中妄想してたのは、現状MAP自動判別が難しいんだったら
MAPデータの提供自体は非同期で外部ツールでやってもいいのかな、と。

まず独自圧縮したMAPデータを用意して、外部ツールと共に配布
使用方法は、狩場に到着する前(Callホムする前)に外部ツールで
指定したMAPデータをMapdata.luaとか決まった名前のFileに展開(2進生データ)
スクリプトからはそれを参照する

と、こんな感じでやれば、容量と処理速度の両立できそうかな

>>665
将来、現在のMAPIDが判別できるようになればMAPID指定して
動的に展開させればウマー

667666 :06/04/18 00:59
SwitchedRunLengthEncodingしてみたところ10%〜15%程度まで圧縮できる事を確認(`A')
decodeも文字列分解すればいいだけなんでluaでもできそうです

luaでdecodeする場合は一度生データを配列に展開しなおしてから
今まで通りに使用する事になると思いますが、速度的にどうなるかわからんちん
そんなところで寝まする

668(○口○*)さん :06/04/18 01:22
くまー?さんのホムAIプログラムを、
自分に取っていらない所はどんどん消してみたら(余計なコメントなど)、
6KB分ぐらい減らしただけなのに、かなり軽くなった?ような気がする。

そういえば、ルアの場合もテキスト自体の容量と、
if文とかの分岐の量も減らすと、読み込みやすくなるのかな?

669(○口○*)さん :06/04/18 01:32
くまさんが容量でかいのはコメントが大量にあるからだと思うが
if文とかループを減らせばそりゃ軽くなるさ。
でも大抵の環境だと大して変わらないくらいのものだと思う。

670(○口○*)さん :06/04/18 02:04
エッヂでつないでるおいらには生命線だぜ

671(○口○*)さん :06/04/18 02:38
>>662
ファイル容量は、今どきのPC事情を考えれば70Mぐらいどうにでも
なるんじゃないかな。DLしたファイルをいくつかCD-Rに書き出すだけで
確保できるんだしね。

次に問題になるのがメモリ。試しにSD2のデータを読ませてgcinfo()を
見比べたら、それだけで2MBぐらい増えてた。
ROクラ自体がメモリ食いまくりなのでこれはさすがにちょっと痛い。
なのでエンコード不要論は撤回。申し訳ない。

まずboolに書き換えてみたけれども、メモリ消費は同じだった。
数値もtrue/falseも変わらないのね。

で、文字列一個にすればそこまでメモリ食わないみたい。
SD2は300x300で、改行を1byteとすると90300文字。
s = string.rep("0",90300)
の結果は+132KB。

だからこういうのでどうだろう。
データを拾う処理も、Luaが変なことをしてなければけっこう軽いと思う。
余計な計算もいらないし。

672(○口○*)さん :06/04/18 02:38
MAP_WALL = string.byte("1") -- 念のため文字コード依存しないように
NEWLINE_LENGTH = string.len([[

]]) --このソースの改行の文字幅

MAP = {x = 5, y = 5}
MAP.data = [[
11111
10001
10501
10001
11111
]]
MAP.dataWidth = MAP.x + NEWLINE_LENGTH

function get_map(x,y)
 x, y = x + 1, y + 1 -- 基準を(0,0)→(1,1)
 y = MAP.y - y -- 上下反転
 return string.byte(MAP.data, MAP.dataWidth * y + x)
end

if get_map(0,0) == MAP_WALL then
 --(0,0)が壁なら
end

データファイルサイズはおおよそ半減。

hex2binに関しては、引数の条件を減らしてライブラリとしての
完成度を高めた方が使い回しが効くし、枯れやすくて安全
…というのはタテマエで、二進数の手計算方法が懐かしく感じて、
それをそのまま実装してみたという話。
ただ使い捨てるんじゃないなら、「一桁しか扱えない」というのを
うっかり忘れて予期しない結果になるっていうミスはありえると思う。

あとコメントが悪いんじゃなくて、decoとかdeco2っていう
直観的じゃない命名がいくないってことね。

673(○口○*)さん :06/04/18 02:39
>>650
utf-8はィェァ…じゃなくてBOMのせいで読めなかったのと、
Map={}
MAP[300]={(略)}
変数名はcase sensitiveなので、nil[300] = {} になってエラーだった。

>>665
たしか cmd /c 経由で実行しちゃって、コンソール窓がうざったいとか
だったと思う。

>>668
luacでコメントのみのファイルと空のファイルをコンパイル
させてみたら、同じ73byteだった。
つまりコメントはluaファイル読み込み時点で捨てられるようだから、
コールホムやハエで軽くなったという以外は関係しないはず。


しまった、夜更かししすぎだ…。

674(*○口○)さん :06/04/18 06:19
ドコまで自分の考えが通じるかはちょぃ眉唾の領域になってきたけど
文字列操作は文字列が長くなれば長くなるほど処理時間が延びたはず。
>>672のパターンだと1回セル情報を取得するたびに143kBのデータレコードに
アクセスすることになって問題ありな気がする
同じ文字列を読み込むなら661の2セル分を1セルの情報に割り当ててしまえば
0,1>0,1,2,3の4値に扱えてサイズ約1/4になるかな


SD2のデータが2M行ったのは
x,yの数値indexと値の3つ×8Byte(型定義が無いので全部double)×300×300≒2Mと予想
それとWinの改行コードは2Byteだったかと

AIには特に関係ないから本当はどうだっていいだろうけどROに限って言うなら今どきのPC事情は通じないと思う。
3,4年前の型使ってる奴の方が圧倒的に多いだろうからね(ノートもそこそこいる
単にFDサイズ以上はデカイと思う古い頭なだk(ry

675644 :06/04/18 08:20
>>660
ソースコードレビューさんくす(笑)
いや、笑ってるけど、まじめに助かる。

>local MoveEx_TargetX = 0
>のミスじゃないかな。

>Luaはグローバル変数がデフォルトだから、
>>外部から見えなくても問題ないはず
>というよりは「見えないようにしたいのに見えちゃってる」だと思う。

そうですね。
いくつかあるMoveEx* でMoveEx_Target*あたりは共有するかもしれない、ってくらいの考えは
ありましたが、基本的にはあのソースのBeginof〜の区切りで独立できるようには書いてます。
#まだMyOwnerとかちょっと入ってるので、切り分け完全じゃないですけど。

676(○口○*)さん :06/04/18 11:19
>>673
>utf-8
アッー
>case sensitive
アーッ!!!
脳内だけじゃなく実環境整えよう・・・

で圧縮の件。いろいろ手法はあると思うけどSRLEでやってみた結果
実データはこんな感じになります(例の如くSD1)

MAP[300]={1F25541}
MAP[299]={1W25541}

MAP[294]={1W41F252WF102WF822WF102WF242WF242WF861W2}

MAP[1]={1W25541}
(F:床、W:壁、H:穴)

どのMAPでもだいたい22KB前後までは圧縮できそうです(現在の15%程度)
伸張は行単位で行いますが、処理速度がどんなもんかは試してなんぼ

677むー ◆MxtFYKfdW6 :06/04/18 12:17
そういえば韓国の桜井サーバのデフォルトAIが更新されたようですね。

手に入れられるならどこが変わったか確認してみたいですね・・・

678(○口○*)さん :06/04/18 13:00
住民番号がないとクライアントすら落とせなくなってるからな・・・

679(○口○*)さん :06/04/18 13:08
どうせ文字列で扱うなら0〜9+a〜z+A〜Zで80進数にしてしまえば
160桁で10進数の300桁を表すことが出来るぜw

っというのは置いといて
AIロード時にファイル読み込み->桁区切り分割->配列に入れる
って処理を1回だけ実行するようにすればそんなにでかくないんじゃない?

MAP読み込み時にファイルを1行ずつ文字列として読み込んで
桁ごとに区切りながらループで配列に放り込んでいく
ファイルそのものは↓見たいにtxtに書いて
11110000111111111
11110000222000011
11110000222000011
11110000000000000
11110000000000000
後は

--gloval
map = {}
--マップファイルから読みこむ
function MapLoad(filename)
  local indexLine = 0
  local indexChar = 0
  local mapLine = {}
  local filePath = ""

  filePath = "./MAP/" .. filename
  for line in io.lines() do
   indexLine = indexLine + 1
   for indexChar, 1, string.len(line) do
    mapLine[indexChar] = string.sub(line,indexChar,indexChar + 1)
   end
   map[indexLine] = mapLine
  end
end

こういうのってだめなのかな?
関数自体は全MAP共通
後は羅列したテキストがあればよくて
1MAP分のテキスト1個が300x300の範囲だとすれば18kバイトですむと思うんだけど

680(○口○*)さん :06/04/18 13:17
コメントなしバージョン書いちゃったのでもう一度・・・
あと計算間違えた
半角1文字は1バイトだから9k
500x500のMAPでも25k
map[x][y]見たいに多次元配列使えるんだっけ?
↑↓のは配列の中に配列突っ込んで2次元にしてるけど

--gloval
map = {}--MAPデータ
--マップファイルから読みこむ
function MapLoad(filename)--読み込むファイル名を渡す(フルパス渡してもいいかも)
   local indexLine = 0--x軸にあたるインデックス
   local indexChar = 0--y軸にあたるインデックス
   local mapLine = {}--x軸1行分の配列
   local filePath = ""--ファイルパス

   filePath = "./MAP/" .. filename --読み込むファイルパス取得
   for line in io.lines(filePath) do --1行をline文字列に読み込む
     indexLine = indexLine + 1
     for indexChar, 1, string.len(line) do--文字列の長さ回数繰り返し
       mapLine[indexChar] = string.sub(line,indexChar,indexChar + 1)--1文字切り出す
     end
     map[indexLine] = mapLine--グローバル配列に1行分のx軸配列を突っ込む
   end
end

681(○口○*)さん :06/04/18 13:21
さらに連投ごめん桁間違えてt
300x300だと90kだね
みんながんばって圧縮してるのはそういうわけかw

昼休み終わるのでこれにて失礼

682むー ◆MxtFYKfdW6 :06/04/18 13:47
MAPファイルへのパスは各AIで自由に指定できるようにしたほうがいいよね。
たぶんみんな自分のわかりやすいようにフォルダ名つけると思うし。

683(○口○*)さん :06/04/18 17:32
ふと思ったんだけど、
OnSKILL_AREA_CMD_ST () -- 設置型スキル使用コマンド状態の処理
とかの、未実装の状態遷移の所は、消しちゃっても大丈夫なのかな?
かなり容量を減らすことができると思ったんだが。

684(○口○*)さん :06/04/18 17:37
まず自分の方針をまとめておくと。
・ファイルサイズには多少はこだわらない(100MB超えたら考える)
・メモリサイズは少なく
・CPU占有も少なく

で、>>674を検証するために手っ取り早くベンチマーク作ってみた。
ついでにstring.byte()とstring.sub()も比較。

500万回ループさせたときのCPU占有時間を取得。
それを10回ずつ行った平均。単位はms。
生データはzip内のresult.txt参照。
http://www.mmobbs.com/uploader/files/163.zip

-- bench1.lua loop: 5000000 -- local v = string.byte(s, l)
str size: 1   ave: 2924.1
str size: 300  ave: 2899
str size: 90000 ave: 2916.3

-- bench2.lua loop: 5000000 -- local v = string.sub(s, l, l)
str size: 1   ave: 3580
str size: 300  ave: 3652.3
str size: 90000 ave: 3653.9

-- bench3.lua loop: 5000000 -- local v = 1
str size: 1   ave: 408.9
str size: 300  ave: 405.7
str size: 90000 ave: 407.5

まず、bench3.luaはループや代入処理そのものの結果。
bench1.luaやbench2.luaの実行時間の大半は文字列操作に
よるものだということが明らかになる。

文字列長 1, 300, 90000それぞれの間に有意な差がないので、
文字列長は処理速度に影響しないと考えられる。

やはりstring型を生成しないことが差になったのか、string.byteの
ほうがstring.subに比べて少々速かった。
ただ一回1ns程度の差しかないので、扱いやすい方を選んでよさそう。

685(○口○*)さん :06/04/18 17:43
ちがう、100nsだ。

>>674
>>671>Luaが変なことをしてなければ
というのも、部分文字列を読むのはCレベルではポインタ操作だから
全体にアクセスすることはないはずなんだ。
DBやファイルアクセスとかとごっちゃになってるんじゃないかなぁ。
もしくは、どっかの言語処理系の仕様とか。

lua_numberの内部表現がdoubleっていうのは正解。

改行コードはたしかにCRLFが普通なんだけど、スタンドアロンLuaの
対話モードで
print(string.len([[

]])
をしたら1(LFのみ)だったから、とりあえず1にしてみた。
90300も90600も(>>671時点で)そんなに差はないだろうと思ったし。

>今どきのPC事情
「今どき」なんて主観的な表現だったのは失敗。
というか自分がその3〜4年前のPC使ってたりもする。

いわゆるリッチコンテンツの分野はともかく、こういった
部分におけるPC性能は、ブロードバンドが普及した頃に
すでに飽和を始めてるんじゃないかな。
4年前にはすでにノートで20GBは積んでるわけだから、
「70MBぐらい」と言ってもおかしな感覚ではないと思う。

とはいえメモリとCPUパワーに関しては、ROクラ自体が
だいぶ食うからケチりたいけどね。
古いPCを心配するならその辺のバランスがいっそう大切になる。

686(○口○*)さん :06/04/18 17:52
>>679
そこまでするならバイナリにしようよw
いや大まじめに、エンコードするならバイナリもテキストも
大差ないと思う。string.byteで10進数化も素直にできるし。

ちなみにtonumber()で2〜36進数(を意味する文字列)を扱えれた。
hex2decいらない子。

展開する部分に関して。
> print(gcinfo())
17 29
> data = {}
> for i = 1, 300, 1 do
>>  data[i] = {}
>>  for j = 1, 300, 1 do
>>  data[i][j] = "0"
>>  end
>> end
> print(gcinfo())
2435 4106
ファイルサイズこそ減るけど、配列に展開しちゃったら
メモリサイズは当初と変わらないという悩みが。

687(○口○*)さん :06/04/18 17:54
>>676
(Switched) Run Length法を使うのは
1.事前に展開すると上記の通り、結局メモリ使用量が2MBほどに。
 そもそもMAP自動判別がない現在、Luaレベルでやる必要がない(>>666)
2.随時展開にはRun Length法自体が向かない

2について。たぶん全ての圧縮手法に言えると思うけど、
Run Length法は一部分だけデータがほしくても
(ブロックの)先頭から展開しなければならない。
圧縮によって冗長性を捨てたことが裏目に出てしまう。
(実装してみたら、誤差程度のCPU占有で済むかもだけど)

展開したものをメモリにキャッシュしていけば通常は
事足りるけれども、最終的には1.5MBほどメモリを使ってしまう。
(展開がブロック単位、ブロックがY軸毎とすると。)

というわけで自分としては、
>>672の比較的シンプルな手法で必要十分で、それ以上は各人の趣味」
という結論になりそう。

>>675
うざいことしてるよなーとか思ってたから、そう言って
もらえてなにより。

読み進めてる途中でちょっと心配になったのが
・経路があまりにも長すぎる
・ルートがケミ視野外になる
という場合だったんだけど、ちゃんと考慮されてるようでGJ。
コード読む限りではロジックに問題なさそう。

あと所彼処に500という数字が出てくるけど、これは500x500
決めうちによるものだろうから、定数を充てた方がいいかも。
万が一変えることになったときに修正漏れをしたら痛い。

688(○口○*)さん :06/04/18 22:30
昔某言語でstringに2Mだか20Mだかの文字列を突っ込んだことがある
文字列操作関数一メソッド実行するのに10msかかりやがった

だが実際はその程度ともいえる
100k程度余裕余裕

689676 :06/04/19 02:04
仕事が終わらんちん。趣味のコード書きたい・・・

>>687
ご指摘の通りで。正直趣味の範囲内ですな
時間とれたらどんな塩梅か実験してみたい処ではあります

そして>>676=666だったりするわけですが
処理速度、メモリ使用量、配布/保管時の容量の両立だけ考えると、
>>666のデータ展開時形式を>>672あたりが落としどころなのかなあ・・・
ただ外部ツール依存はメンテナンス考えると微妙なりー
と言い出しっぺながら思うところではあります

まあDataFormatさえ決まってしまえば、他は後からでも
なんとでもなるかーと思いながら仕事へ戻るッ

690644 というか MoveEx()の人 :06/04/19 06:59
>>687
>あと所彼処に500という数字が出てくるけど

あ〜。確かに。
ROのマップサイズなんて意識したことなかったんで、500幅確保すればだいじょぶかな?
って感じでてきとーに切ったのは事実。
提供してもらったmap情報にMapWidthみたいな情報あるから、これを参照するように
するといいかもしれない。

他にもあちこちにマジックナンバーは埋まってるから、直したいね(^^;;

691(○口○*)さん :06/04/19 23:34
すいませんちょっと謎な現象が起こっているので教えてください
AIに自動でスキルを使わせて戦わせたいのですが
使ってくれません( ´・ω・`)
TraceAIで確認したところ

Call API: SkillObject(18480, 5, 8013, 58803)
とちゃんと関数をコールしているっぽいのですが
実際は発動しません

…ひょっとしてケミが座ってると物理攻撃はしても
スキル攻撃しないとかなのでしょうか汗

692(○口○*)さん :06/04/19 23:36
>>691
はいその通りです。
ケミが座っている状態ではホムもスキルを使えません。

693691 :06/04/19 23:51
素早い回答ありがとうございます

やっぱそうだったんですね汗

ケミのモーション見て座ってるときは物理攻撃するよう組み替えます

694(○口○*)さん :06/04/20 09:19
ふと思ったんですが、
モンスターデータライブラリを参照して、
TraceAIでおよその累計経験値を出力するのって可能ですかね?

695(○口○*)さん :06/04/20 09:30
共闘人数の計測
ダメージ比率の計測

この二つのうち後者はほぼ計測不可能
(ホムの攻撃成功失敗ミスの判定ができないため)
前者も正確には取れない
(食いかけとか)

ホムだけが攻撃する監視自動狩りならできるだろうがね

696(○口○*)さん :06/04/20 09:39
はい、それは承知で、およそと書きました。
ほんとにふと思っただけで、使うつもりはあまりないんですw

わざわざ返答ありがとうございましたm(_ _)m

697(○口○*)さん :06/04/20 10:22
そもそも倒したかどうかって結構判断するのめんどくさいよね
10万ルールで死体の数でも数えればいいかな?

698(○口○*)さん :06/04/21 20:14
スキル使用するとまず追尾状態に移行するけど、
いきなり攻撃状態にしても問題ないよね?
攻撃状態で、距離が悪かったら追尾状態になる、って書いてあるし。

699(○口○*)さん :06/04/21 20:17
問題はないかもしれないけど意味あるか…?

700(○口○*)さん :06/04/21 22:30
反撃されずに初撃スキルが撃てるな。スキルは離れてても当たるから。

701(○口○*)さん :06/04/21 23:13
攻撃状態に移らずスキル使えば?
うちでは初撃スキルはIDLE_ST->CHASE_STのところ

702(○口○*)さん :06/04/22 01:24
逃亡AIを組んでみた。
敵の進路方向に、ホムが逃げるな感じです。
これだけだと、ホムが画面外に敵から逃げてしまって大変な事になる事がorz
ケミから、離れすぎたらどうするかの処理に悩み中です;;

これ作って思ったんだけど、敵の進路方向?って変わりすぎw
ホムが、変にジグザグな動きになりますorz

local ownerX, ownerY = GetV(V_POSITION, GetV(V_OWNER,MyID)) -- 召還者の位置を得る
local homX,homY = GetV(V_POSITION, MyID) -- ホムの位置を得る
local x, y = GetV (V_POSITION,MyEnemy) -- 敵の座標を取得して
local MoveCell_X
local MoveCell_Y

MoveCell_X = homX+(homX-x)
MoveCell_Y = homY+(homY-y)
Move(MyID,MoveCell_X,MoveCell_Y)

703(○口○*)さん :06/04/22 02:48
マジスレテンプレを見ると敵の移動について理解しやすいんじゃないかな。
FWに関する辺りがオヌヌメ

704(○口○*)さん :06/04/22 13:14
>>702
前にショートレインCRをやりやすくするために、
適当な数を集める → ケミ中心にサークルトレイン → ケミの右方向からケミとすれ違う
っていうの作った時のノウハウだが、
以下のコードみたいに一定距離離れたかを監視させておいて、主人との距離ごとに次の目標地点を決めるといいかも


--トレイン中主人から一定以上の距離があいている場合、次の移動先を決める
if ( 5<=GetDistanceFromOwner (MyID) ) then
x,y = Calc_NextMovePoint() ---702さんはここに適当な逃亡AIを追加すればいいかと
Debuglog("next move point",x,y)
return
end

--主人から大きく距離があいている場合、追尾を中止し戻る
--主人がホムからはなれる方向へ移動したときは、こちらのコードが実行される
if (9<=GetDistanceFromOwner (MyID) ) then
MyState = FOLLOW_ST
TraceAI("ATTACK_ST -> FLOLLOW_ST")
return
end

7051/2 :06/04/22 15:36
工体AIが BBガーターMAPの中の人のMAPに対応したので以前出ていたMoveExを組み込んでみました。
工体AIへの修正はAI.luaからMovelib.luaを呼び出すようにimportの先頭に"Movelib"の追加
event.luaを検索してLoadMapFile( mapcode )を実行している後ろでLoadMapBBData()※1
の呼び出しを追加。
その他Move関数を呼んでるいるところをMoveExへとぺたぺた書き換えました。

function LoadMapDataを改造し、 BBガーターMAPの中の人の設定ファイルを参照しました
※1
function LoadMapBBData()
local x,y
local pos
local buf
local curdata

for y =MapHight,1,-1 do
for x= 1 , MapWidth do
curdata = CheckCell (x,y)
if curdata == nil then
SetMapData( x,y,CELL_UNKNOWN)
elseif curdata == 0 then
SetMapData( x,y,CELL_AVAILABLE)
else
SetMapData( x,y,CELL_NOTAVAILABLE)
end
end
end
TraceAI( "LoadComplete.")
end

7062/2 :06/04/22 15:41
--tab 消えちゃった、ごめん。

んで、Movelib.lua を 実行していたらいくつか問題が出たので
その修正内容を。

1. mod()を呼び出している部分でエラー -> math.mod() へ変更

2.701行目の
 TraceAI ( string.format("PushQue(%d,%d)%d", mod(curcell+500,500),math.floor((curcell+500)/500) , workmap[curcell+500]))
 で、エラーになったのでコメントアウト。(workmap[curcell+500]がnilっぽいです)

3.同じ関数の697行目、710行目でresultに値を設定しているが、無限ループから抜け出せないっぽいので
 その次の行で return resultの追加

4.同じ関数の705行目、706行目でstartx,startyに値を設定しているがcurcellへ反映されていないので
 その次の行で
 curcell =startx+ starty * 500

5.729行目のGetV(V_POSITION , MyOwner)でMyOwnerが未定義だったので
 GetV(V_POSITION , GetV( V_OWNER, MyID ))へ、変更

大体問題なく動いてる気がしますが、これからしばらく狩りで使って
動作を確認してみます。

MoveExの中の人へ報告したほうがいいんですかね?
このスレでおk?

7073/2 :06/04/22 15:49
うーん、動かしていたらやっぱりSelectRoutの中で、
無限ループにつかまってしまったようです。

もう少し考えてみます。スレ汚し失礼。

708MoveExの人 :06/04/22 16:49
>>705〜707
情報感謝です。
こちらも実装がほぼおわり、デバッグその他を進めているところ。
本日中に最終版を出すと思います。

で・・・707でのご指摘の点では問題が1箇所わかっているので速報しておきます。
CreateMap() で検索ルートを作成する際に、到着点がそもそも進入禁止だった場合に
無限ループに突っ込んでしまいます。
なので、CreateMap()内の最初のほうで
Stack_cur[1]=0 となっているところを、

if( SetCellPriority(startx,starty,0,0) == 0 ) then
-- そもそも検索開始点(マップ上の到着点)が進入不能。
return false
end

・・・という感じに置き換えると、改善されると思います。
現状上記状況で半日ほどうろうろしてますが、今のところ特に問題になっていません。

・・・MAP情報のSHIFT-JIS変換がめんどくさいです(笑)

709MoveExの人 :06/04/22 16:53
Σ('-'つ)つ
いきなり大嘘書いてるし・・・

workmap[ startx + starty*500] = 0
となっているところを、

if( SetCellPriority(startx,starty,0,0) == 0 ) then
-- そもそも検索開始点(マップ上の到着点)が進入不能。
return false
end

・・・です。
スレ汚し失礼。

710705-707 :06/04/22 17:09
4番の指摘については、こちらの勘違いっぽいです。
失礼しました。

ちなみにShift-JISへの変換とMap->MAPへの変換は
それぞれVectorで適当に検索して
ttp://www.vector.co.jp/soft/win95/util/se326595.html
(KanjiTranslator)

ttp://www.vector.co.jp/soft/win95/util/se323564.html
(Repl-Ace)
で行いました。ツールはいろいろ有るとは思いますが。
参考までに。

711705-707 :06/04/22 17:19
709の対策をやってみたところ、問題なく動きました。
新バージョン楽しみにしています。

712MoveEx()==Glenelgの人 :06/04/22 19:03
ということで、動作テスト完了したので、MoveEx()を盛り込んだAIをリリースしました。
現状、うちのAIと組み合わせた形でリリースしています・・・ライブラリ部分だけ別アーカイブにする
ことも別途考慮しますが、まずはAIと抱き合わせにて失礼(^^;;

ttp://tomose.dynalias.net/RO/index.php?%A5%DB%A5%E0%A5%F3%A5%AF%A5%EB%A5%B9AI

上記705-707あたりで指摘がなされたバグ修正の他に、もうちょっと滑らかに移動できるような
アルゴを追加しています。
(以前は複数に分割した軌道の交点に必ず立ち止まるタイミングがあったのですが、
 多少のカーブなら先読み的に移動することで立ち止まるタイミングを減らしています)

多くの方のご指摘・ご意見をいただき、大変助かりました。
最初にお話したように少々オーバースペックではありますが・・・興味があれば、ぜひ。

713(○口○*)さん :06/04/22 19:56
>>710
工体の人のところのコメントのところに
修正したひとのMAPが載ってる

714騎士子さん :06/04/22 20:27
アーッ!!直してなかったんだっけ

という事で既に自力でやられている方もいらっしゃいますが
修正版をうpしておきました。

ttp://sakage.main.jp/ro/mapbb/lua/maplua.zip
やっぱり1.9Mですよねpgr
圧縮したいなあ・・・

現状はこんな↓感じです。吐き出すときにSJIS変換、MAP{}の修正だけです
ttp://sakage.main.jp/ro/mapbb/lua/in_sphinx1.lua

とりいそぎいじょう

715(○口○*)さん :06/04/22 20:40
あと一点。現在File直リンしておりますが、
れんたる鯖の規約に抵触する気もしますので
いずれわんくっしょんページを入れる事になるやもしれませぬ

ぷりーずぎぶみー暇ッ!!

716(○口○*)さん :06/04/22 21:47
>>714
こんなんでいかがでしょう
http://www.774.cc/clip/img/EkqIA7qrxw7k5cullqvI.html

717(○口○*)さん :06/04/22 22:00
>>716
7zip( ゚Д゚)ウマー

も、そうなんですが、生データの方を圧縮したいです><
配布/展開後のHDD容量はともかく、実行時のメモリ圧迫がィャンな気分

718(*○口○)さん :06/04/23 00:41
300*300の2次元配列のindexデータだけで約1.5MB程食うから
やっぱ使用メモリ量の削減は配列その物を使わなくしないと意味無いかな・・・
>>672でもいいんだけど、同じ容量になるなら256色BMP画像の1画素(1Byte)から
string.byte読み込んでWALL,FLOOR,HOLEを返すのを試して、一応成功しました。

ioから変数にバイナリのままデータを格納しているのでメモリも
例のごとくin_sphinx1でファイル容量分の90kB程に収まります。
加えて画像なら見た目でそのままドコのMAPか分かるから管理も楽かなと

ただ、読み出し自体は>>672と変わらないから無圧縮BMPのみ読み出し可
それとMSペイントと写真屋で微妙にヘッダ情報が異なる(4Byteずれる)
のがややこしいけど自動認識は出来そう。(他の編集ソフトは持ってないですorz

ファイルはびーびーさんの画像を縦横50%縮小してBMP保存だけで行けます。

719(○口○*)さん :06/04/23 02:54
>>718
キャ━━━━(゚∀゚)━━━━!!
BMPはナイスアイデア!ただのバイナリでもいいかなと思ってたけど、
それと違って「見える」というのはいいね。
8bitにしないで2bitBMPでいいかも。もしくは崖データを使わない人も考慮して
壁データ1bitBMP+崖データ1bitBMPとか。
データ量はおおよそ23k。(壁のみなら半減)

>微妙にヘッダ情報が異なる(4Byteずれる)
4byteの正体はわからないけれども、0x000aにデータの開始位置情報があるから
そこを見れば大丈夫なはず。
あとは画像の幅と高さだけ読み出せれば、ヘッダの他の部分は読み捨ててよさそう。

720(○口○*)さん :06/04/23 03:23
>>719
解釈するのには二値画像のが楽そう
壁データと崖データばらすって発想いいなぁ

721(○口○*)さん :06/04/23 09:41
あ、BMPに浮かれてすっかりわすれてた。
読み出しは1byte単位になるから、それをbitにバラす計算させないといけない。

でも効率云々じゃなくて、BMPで実装してみたいw

722騎士子さん :06/04/23 13:47
>>718
(・∀・)!

面白いですねー。
今のBBMAPは2倍拡大してBB線の色合成、gif化してるので
その工程を省けば8bit、2bitBMPも吐けますです。
ので、ライブラリの中の人が必要でしたらご連絡くださいませ

こちらの近況は、圧縮したデータを配列に読み込み(現行比15%くらい)
「展開しないまま」ロジックで有効Cellを判断させる感じで書いてみてます。
もんもん

723(*○口○)さん :06/04/23 20:46
現状の>>718だとパレット番号で判別していて、厳密には色で判別はしていないから
パレットの中身を並べ替えられると誤認識します。パレットの中身も読み込んで
判定すれば2,16,256色(1,4,8bit)全部対応できるけど・・・ちょっと面倒かな^^;
でも時間さえ許せば純粋にやって見たい課題

bitにバラす計算についてはama_dun01をx,yのループでx=MAP.Read (x,y)やった感じだと
GetTickでループ終了に8bitBMPが約70ms、4bitBMPが約240ms、1bitBMPが約470ms、
ループ回数で割れば1回の読み出し自体は誤差範囲かな>4bitBMPが3μs、1bitBMPが7μs
Gvとか処理時間の極限を追求しないのであれば、1bitBMPも十分実用範囲


>>719
崖打(壁穴)データはWALLとFLOOR&HOLEの2値、壁データはWALL&FLOORとHOLEの2値で
スキル使用時と移動時で異なる1bitBMPを読むのは案外いいかもしれない
MAPファイル数が2倍(約700)になるのが多い気はするけど
建物内部、ケミクリが進入不可のMAP等はファイルなしと割り切れば大丈夫かも
更に崖打データ不要MAPをリスト化しておいて適宜対応できる
工体風htaとAPI関数が作れれば1bitBMP2種もいい感じ


>>722
一括でファイル出力しないとパレットの並びが不一致になるかもしれないのでお願いできると助かります^^
その時は8bitBMP(256色)と1bitBMP(2色モノクロ)の2種類をお願いしたいです。
4bitBMP(16色)は壁穴データはあるけど読み出しが少し遅い
中途半端な位置合いになりそうで扱いが難しい所・・・・・

724(*○口○)さん :06/04/23 20:48
>x,yのループでx=MAP.Read (x,y)
q=MAP.Read (x,y)とか適当な変数に代入ですorz

725(*○口○)さん :06/04/23 21:54
更に修正
>崖打(壁穴)データはWALLとFLOOR&HOLEの2値、壁データはWALL&FLOORとHOLEの2値
崖打(壁穴)データは「WALL」と「FLOOR&HOLE」の2値
壁データは「WALL&HOLE」と「FLOOR」の2値 ですorz

726705 :06/04/23 22:58
>>MoveEx()の方
新バージョンいじってみました。
MoveSt()で使用している変数が
charID や charaID だったり
targetx や targetX で
targety や targetY だったりしているみたいです。

今のAIでは使っていなそうなので問題ないとは思いますが
ちょっと気がつきましたので、一応報告。

727MoveEx()の人 :06/04/23 23:34
>>726
あわわ。
あれ、MoveSt()、削除してなかったですか・・・
削除してから出すつもりではずし忘れてたみたいです。
ご指摘感謝。

728(○口○*)さん :06/04/24 21:17
スキルリセットでバイオプラントを取ってジオ呼んでみたら、
ホムがジオを攻撃してきたorz
なんとかならないかな?

729(○口○*)さん :06/04/24 21:19
>>728
アルケミスレテンプレサイト
http://cgi.f31.aaacafe.ne.jp/~alchemi/pukiwiki.php?

730(○口○*)さん :06/04/25 00:01
>>728
まず、だ。要望はコッチで聞いたほうがレスがきっとはやいぞ。

ホムンクルスAIについての雑談・要望スレ
ttp://enif.mmobbs.com/test/read.cgi/livero/1142513331/

そして、だ。その問題は23日に取り上げられたばかりだ。

ホムンクルスAIについての雑談・要望スレ
ttp://enif.mmobbs.com/test/read.cgi/livero/1142513331/799-803

731(○口○*)さん :06/04/25 00:03
>>728
それと、もしもだけど他人のホムが攻撃してきて困る、ってのなら、
自分のAIではどうしようもないからそのホムの飼い主に「攻撃しないで」ってお願いしなさい

732(○口○*)さん :06/04/26 00:29
>>723
遅くなりましたがぶんなげておきました。

今思うのは減色るーちん書くより普通にbmpフォーマットで自前出力
した方が楽だったかも新米・・・

733(○口○*)さん :06/04/26 18:33
工体ツールできたね

734(○口○*)さん :06/04/28 01:45
>>723
穴がない(通行可能MAP=攻撃可能MAP)は考えてなかった…。
どこにその情報を持たせるのがスマートなんだろう。

パレットのことを気にしているけど、あくまでもbmpの形式に則っただけの「専用データ」なのだから、
ビット立っていれば(パレット1なら)通行可能という程度でいいと思う。
フォーマットをしっかり決めるということだね。

なので提案。

1bitの場合は「移動可能MAP」「攻撃可能MAP」の二種で、0なら不可(壁)、1なら可能(通路or通路+穴)。
2bitの場合は下位bitを移動可否、上位bitを攻撃可否に。つまり00壁、10穴、11通路。
4bit、8bitの場合は2bitと同様の形式とし、余分な上位bitは0で埋める。
AIライブラリは色を無視をする。視覚的に確認する際に都合の良い色をつけることができる。

こういうフォーマットでどうかな。

>>732
見つかりません…。orz

735(*○口○)さん :06/04/28 08:28
>>732
お願いしておきながら反応遅くてすいませんorz
今週ちょっと立て込んでいて割と時間が無いですが何とか時間とって癌ばります。


>>733
1.luaの仕様上、データの読み込みはByte(8bit)ごとになるのでbitバラシが必要>>723
2.ペイント(ドロー)ソフトに2bitのビットマップが無い(1,4,8bitが実用範囲)
3.ペイント(ドロー)ソフトにパレットデータが並び替えられる可能性がある

1は1,4bitでは必ず必要なので仕方無いです。2はお察しくださいorz
3はパレット番号00,10,11(0,2,3)が00,01,10(0,1,2)に並べ替えられる場合があるので要注意なのです。
既存の画像フォーマットで書き換えが行われるので画像である以上、luaはそれに従うしかないです。
見やすい色としては壁黒、床白、穴灰、辺りが妥当なのでパレットから該当色のパレット番号を探し
その番号から00壁、11床、10穴、等動的に割り当てるのが今後の(やりたい)課題ということです。

>>718に書いた通り、既に1,4,8bitのbmpから読み出し>壁0、床1、穴5を返すことは出来ているので
移動用のコメントと、攻撃用の関数群を書き足す所です。(650の壁1、床0、穴5も出来る様に
移動と攻撃が同じ、穴のないMAPはファイル節約の為に外部に該当リストを持たせて、
移動と攻撃でどの画像から読み込むかを指定(工体さんのhtaを拡張)出来ればいいなぁと・・・
ぎぶみー暇!

>>732はうちのサイトの方のコメントフォームに来てました。
MapReaderを手直ししてから一緒に更新しようと思っていましたが、
必要であれば先にファイルだけ上げて置きます。

736(*○口○)さん :06/04/28 08:31
誤記
>>733じゃなくて>>734です_| ̄|○

737(○口○*)さん :06/04/28 09:07
>>735
なるほど、たぶん立場が少し違うかな。
・bmpをデータとして読み込む
・データファイルをbmpとしても読める形にする(自分はこっち)

パレットを勝手に並び替えるようなフルカラー前提設計のペイントソフトなんて
非対応でいいじゃないかとか考えてたり。
個人レベルで書き換える必要のあるものじゃないしね。
(まぷーびーびーの中の人に都合が悪いというなら、話は別…)

必要なら、パレット整理する変換スクリプト書いたっていいかもしれない。

あとこちらでも1bitのデータ列から読み出すところは完成。
今のところ1bit特化・API非互換でいく予定で、APIに悩み中。
IO周りはまだフォーマットが不透明なので後回し。
問題なければファイルupお願いします。

ってあああ、減色ルーチンかっ!

738(○口○*)さん :06/04/28 10:00
伺かみたいにマップBMIPの左上端から1つ目を道、2つ目を壁、
みたいにしておけばパレット番号や色の影響は受けないかな。
一ライン追加する必要がでてくるけど

739騎士子さん :06/04/29 18:12
ふぉー!久しぶりに休みです(でした)ぜ

>>735
いえいえ。
それから8bitはmだ手つけてません。最初から8bitで作ればいいんだろうけど・・・

>>737
・bmpをデータとして読み込む
・データファイルをbmpとしても読める形にする(自分はこっち)

実は自分も後者を想定してやろうとしてました
元々RO自身が提供するデータをimage化してるだけだったので。
ROデータの冗長部を削って圧縮データ作ればいいかなあと
(表示とluaへの提供はツールで実装)
まあ頓挫してますけど(´^ω゚`;)

あとパレットは意識してなかったり
元々使ってた開発ツールが自力ではgif出力できなかったもんで
gif出力についてはPG内からIrfanViewを使用してたりします

740騎士子さん :06/04/29 19:01
・・・・・ちょっと待て
1bit減色も8bit減色もIrfanView使えばできるんじゃまいか?







アッーーーーーーーーー!!

741(○口○*)さん :06/05/01 02:49
どうしたんだこの停滞は・・・

742(○口○*)さん :06/05/01 15:01
マップ話続いてるから雑談に逃げた漏れみたいなのが多いか、
単純に語るネタがなくなったか。

743(○口○*)さん :06/05/01 18:20
MAPデータは使わない人はとことん使わないからな。
何か話をしたい人は雑談スレにいってるんじゃなかろうか

べつにMAP談義が悪いわけではないが、最近覗いてもこの話しかない感じだから
覗くことすら稀になってきた。

744(○口○*)さん :06/05/01 18:32
MobIDとかもそうだけど外部データ使用には抵抗がある人もいるしね

745(○口○*)さん :06/05/01 18:47
停滞してるのは、ある程度機能が満足されてきているから、ですよね。
AI雑談スレでも「MVPボス対策」みたいな要求はあるにはありましたけど、
本質的に新しい要求ってあんまりないですし。

かくいう私も、いちおーマイナーAI提供者ですが、ここに公開するほどの新ネタもないので、ROMってました。


>>744
確かに。
でもまあそういう意味だと、現状のホムAIへのクライアントからの情報が少ないってのが本質的な問題だよね。

マップ情報は、本来(ユーザーがクライアント上のカーソルで判断できるように)ホムAIからの要求で
クライアントが提供するのが正しい姿だと思うし、
MOBIDだって本来は「クライアントから(ユーザーがクライアント画面上の絵&名前で判断できるように)
ホムAIからの要求でクライアントが提供するのが正しいと思うし。

746(○口○*)さん :06/05/01 19:22
>>745
確かに・・・
MobIDについてはV_HOMUNTYPEじゃなくてV_OBJECTTYPEになって
どこかにID一覧でも置いてあれば問題ないわけだしね

つまるところ
http://www.mmobbs.com/shigoto02.jpg
正確には重力だけど・・・

747(○口○*)さん :06/05/01 22:53
MAP情報はなくたって(というかそれで困ってる人のほうが少ないくらい)
プレイできる類の情報だから、喰らいアアンとから返すようにはまずならないだろうな

748(○口○*)さん :06/05/02 00:44
まあ、そう後ろ向きに考えるのはよしましょうよ(^^;;

確かに今までのガンホー・グラビティの動作から見て実装されないだろうと思いますけど、
そういう需要がゼロじゃないことは、このスレで「マップ情報を作ろう」の話が進んでいるのを見ればわかる話。
それ以外の話題が出ていないということと比較すれば、当面はマップ情報って優先度の高い話ってことじゃないですかね?

使うかどうかはAI作者次第ですし、現状の動作で満足できている人には無用な情報かもしれませんけどね。

749(○口○*)さん :06/05/02 02:16
後向きというより、取らぬ狸の皮算用にならないようにしておいたほうがいいということじゃなかろうか

優先度つっても、単純にMAP判定部分がAI化しにくいだけで、他の優先度が高いものはすべて
なんらかの形で実現されたってだけだろうしね。

なくてもすむ機能である&もともとAI変更をオマケ程度にしか考えてない重力あたりからすれば、
「提供されている機能の範囲内でお楽しみください」
としか答えないんじゃないかな。

クライアントからのMAP情報取得はまずないものとして(現状のまま)考えていくべきだろうね
あっても、MOVEの移動先が進入不可かどうかを返してくれるくらいだろう。
(射線上の障害物なんかに関係なく)

750(○口○*)さん :06/05/02 02:16
>>747
どうでもいいけど色っぽいな。喰らいアアンと。

751(○口○*)さん :06/05/02 03:22
流れをぶった切って開発者方々に質問
皆はどこまで自動する?

俺は手動のサポート程度にするつもり

主人の命令を挟む余地を残しつつ
最低限の基本戦闘と移動、主人の補助をする動作を入れて、
あとある程度AIに満足したらお遊び機能を増やしていくつもりなんだが

752(○口○*)さん :06/05/02 03:22
×自動する?
 ↓
○自動化する?

だ、誤字スマン

753(○口○*)さん :06/05/02 08:41
>>751
俺の感覚では、もともと「本来プレイヤーが操作すべきところを多少手抜きできる」くらいの
感覚なので、似たような感覚かな。PCの前に座っているんだから、完全にAI任せにする必要もないし。
それに、プログラムではプレイヤー間の微妙な機知は察してくれないので、AI任せなんて怖くてできない。
完全に自動化したモノの動きの冷たさは、ROプレイヤーならみんな知ってるだろうし。

大体「自動化」と言っても、現状の多くのAIで基本的な戦闘はほぼ自動化できているはず。
これ以上、何を自動化するや?って疑問もあるけど。

754(○口○*)さん :06/05/02 10:44
「語る」スレだし技術的でないこういう話も悪くないね

基本はほぼ自立思考
何かあったときは主人が軽く調整してやる感じかなぁ
今のところは下水とかSD行かないからMAPは必要ないけど

ただ、最近思考モードが増えてきてどう管理していくか悩み中

755(○口○*)さん :06/05/02 12:29
基本AIに沿って多少いじった程度。
婆園特化にして邪魔なウィスパーを優先的に倒すとか、オートスキルとか
主人が殴る敵にシンクロさせるような使い勝手をよくはしてるけど
配布されてるような汎用性は今のところないんだよな。
ソース最初から組みなおしたいけど仕様かたまらなくて

756(○口○*)さん :06/05/02 13:19
戦闘機能なんてほっぽって溜まり場で芸ばかりさせてます。
そして私は「完全にAI任せ」にしたい。
いや、主人の言うことにただ従うだけじゃなくて、
自分で考えて(るように見えるよう)動いてくれるといいなと。
ときどき(しょっちゅう?)間違いもするけど、馬鹿な子ほどかわいいのさ。

757(○口○*)さん :06/05/02 14:24
私は、自動化というより学習をさせたい
やっぱりAIと謳っているのだから
デフォルト以外の基本的な処理が
外部データからの検索だけでは少し寂しい。
デフォルト+外部データの自動書き換え+外部データの検索で
ある程度学習しているように見せかけようとしている

ソース最初から組みなおすとデバッグに骨が折れる・・・

758(○口○*)さん :06/05/03 01:54
戦闘で時に予想外の方向に行ってしまうのは、かわいい。
スキルのランダム発動は、それほど面白くない。

たまにホムが付いてくるのが遅れるのは、かわいい。
ホムがケミの周りを延々と回り続けていると、止めさせたくなる。

ペットが喋るのは不評。
ホムにエモーションは実装したい。

上手く言葉にできないけど、面白いAIにしたいとは思う。

759(○口○*)さん :06/05/03 20:44
自動学習して欲しいといえば、自分のHIT率と回避率、防御力。
ホムのHIT率ではなかなか当たらない敵、避けれなくて高ダメージ受ける敵などには、
カリプス連打するというのを入れてるんだけど、レベル上がるたびに
設定ファイルにHIT、FLEE、DEFを書き直すのが面倒。
そこをどどうにかしたいのだがHIT,FLEE,DEFを書き直す手間のほうが、
AI書き直すより楽なんだよなぁ。
ネタはあっても実現するだけのメリットが感じられないことのほうが、
最近多くなってきたと思う。

760(○口○*)さん :06/05/04 20:13
functionとlocalのちょっと意外な落とし穴。

-- 1.ok
function f1() return g1() end
function g1() return true end

-- 2.nilエラー
function f2() return g2() end
local function g2() return false end

-- 3.ok
local function g3() return true end
function f3() return g3() end

-- 4.ok
function f4() return g4.call() end
g4 = {}
function g4.call() return false end

-- 5.nilエラー
function f5() return g5.call() end
local g5 = {}
function g5.call() return false end

-- 6.ok
local g6 = {}
function f6() return g6.call() end
function g6.call() return true end

4のパターンの延長やJavaのprivateあたりの感覚で、公開不要なものにがしがし
localつけたら2や5のパターンになってハマった。orz
よく考えれば、関数が定義された瞬間にはまだlocal宣言されていないから、
その関数のスコープ(クロージャ)に含まれないのね。

761(○口○*)さん :06/05/05 21:25
俺は、今の自分のホムと、ケミに合わせていろいろAIを変えてるな。
今は、
「SP自然回復量以下のスキル、月光の使用」←これでほぼ無限に月光を撃てる
「HPが減ってきたら逃亡しながら月光Lv5」
のみでしてるが、それだけでも十分行ける。
まあ俺も、敵によって攻撃の仕方を変えれたらいいなとか思ってたりする。

762(○口○*)さん :06/05/05 22:02
>>761
敵によって動作を変える、か。
MobIDごとに動作を変えるようにすると、
ロジックがMobの数だけ出来てしまうから現実的ではないなあ。

Mobの「属性」や「種族」によって動作を変える、くらいが適度だと思うんだがどうかね。
mobdataを読み込んでおくことが前提になるが。

763(○口○*)さん :06/05/05 22:19
敵のHPを定数で割って、その敵に使用するスキルの回数を決めたりとか。
ところでホムにとって属性や種族が判断材料になる局面ってあるのかな。

764(○口○*)さん :06/05/05 22:33
あんまりなさそうだけどバニルに限れば
聖や闇のときはカプリス使わないとかそんな感じかな。

765(○口○*)さん :06/05/05 23:38
カプリスは影響あるけど>>764くらいのしかないな。
通常殴りは属性影響ないし、種族もあんまり関係ないし。

どっちかというと主に行く狩場での「強敵」「楽な敵」「雑魚」くらいの区別のが処理しやすいと思う。

766(○口○*)さん :06/05/06 12:08
なるほど、強さで分けるって事はGD2なら、
1:ゾンビ・ドレインリアー
2:グール
3:ジャック・ナイトメア

こんな感じに分けて、攻撃パターンを変えてみるって事ならできそうだ。

767(○口○*)さん :06/05/06 12:54
別の視点でいくとmobの攻撃順位ね
今導入しようとしてるんだけどGetOwnerEnemyとGetMyEnemy統合しないと
うまくいかないから面倒い

768(○口○*)さん :06/05/06 14:59
>>759
ある程度のレベルまでくればHitFleeDefは成長率から算出するって方法もあるよ
そうすればLvだけ書き直しでいけなくない?
Hit=Lv+(Dex成長率*Lv)
Flee=Lv+(Agi成長率*Lv)
Def=(Vit成長率*Lv)/3 ※
って感じで定数にしてやれば書き直しはLvだけ済むはず
レベルが50も超えれば、それほど成長率に誤差は出ないだろうから
目安としては使えるんじゃないかな
※乗算DefはウチのバニルなんかだとVitの3分の1程度なのでこの式

769(○口○*)さん :06/05/06 16:51
計算ややこしくなるし精度も下がると思うけど、
MAXHPは取得できるからここから逆算繰り返していけば
自Lv設定もしなくてもいける気がする。

770(○口○*)さん :06/05/06 20:19
/* -------- 俺用メモ --------------
CreateNamedPipe を使うと、
リアルタイムで外部プロセスとデータをやりとりできる。
デバッグ出力等に有効ではないだろうか。

-- 通信用パイプオブジェクト
pipe = nil

function AI(id)
-- 通信用パイプ作成
if( pipe == nil ) then
pipe = io.open("\\\\.\\pipe\\TestPipe", "w")
end

-- パイプにデータを出力
pipe:write("test")
pipe:flush()

...

end
-------- 俺用メモ -------------- */

771(○口○*)さん :06/05/06 21:42
--[[ 自分用メモ:あとで詳しく調べる
io.pipe(だったかな?)がLuaのデフォルトで殺されているようだったから
pipe類一切ダメなんだと思ってた。

でもこれマズくない?
]]

772(○口○*)さん :06/05/07 06:23
if (motion == MOTION_DEAD or motion == -1) then
の逆は
if (motion ~= MOTION_DEAD or motion ~= -1) then
だろ、とかって1時間悩んだのは私だけでいい。

773(○口○*)さん :06/05/07 08:20
>>772
逆をどういう意味で捉えるかによると思うのだけれども
逆の意味が否定と同じ意味と捉えるなら
motion ~= MOTION_DEAD and motion ~= -1
が正しい否定の形ではないかと・・・

774(○口○*)さん :06/05/07 09:12
「andの否定」は「否定のor」と同論理、というのは基本ですね。
・・・というか
not( motion == MOTION_DEAD or motion == -1)
・・・じゃダメなんかい?(笑)

775(○口○*)さん :06/05/07 09:21
not (P or Q)
→not P and not Q
ド・モルガンの法則…なんて呼ぶと懐かしいなぁ。

776(○口○*)さん :06/05/07 09:38
>>773,774
さっきド・モルガンの法則を復習したつもりだったのに・・・。
逆、は否定、ってことです。
(motion == MOTION_DEAD or motion == -1)==false を暫定の処置にしてましたが
どっちがスマートか、どっちが分かりよいか、といわれれば・・・ううむ。

それだけだとアレなので、既出とか気にせずに気になったことを。
target = GetV(V_TARGET,MyOwner)
で得る主人のタゲって、テレポの類をするとかそのタゲを変えるまで保持される、で合ってる?
倒しても画面外に離れても変わらないみたいで。
それで困ることなんてあんまりないだろうけど。

777(○口○*)さん :06/05/07 09:57
主人のタゲはテレポしてもリセットされなかったような。

778(○口○*)さん :06/05/07 10:03
>(motion == MOTION_DEAD or motion == -1)==false
いかにも場当たり的な修正に見えるというかw

わかりやすさを求めるなら
function isDead(motion)
 return motion == MOTION_DEAD or motion == -1
end
条件式に名前を付けてしまって
if not isDead(motion) then
とか。
結果的に>>774だけど。

テレポしてもタゲ忘れないっていうのは、mobのテレポ無敵無視の原因だと思う。
Gvと違って、テレポやWP移動の無敵は「タゲられない」だけのはずだし。

779(○口○*)さん :06/05/07 13:55
ケミのタゲがリセットされない、と、ケミがタゲられてるのがリセットされない、を混同してないかい
つか、テレポした側がタゲ保持してる、と、テレポしても敵からのタゲが外れない、
の混同かな

780770 :06/05/07 15:37
とりあえずpipeを利用したAIデバッグ窓を作ってみた。
ttp://www.mmobbs.com/uploader/files/210.zip

ひたすらListBoxにデバッグ出力が追加されていくので、
あまりずっと垂れ流してるとメモリがパンクすると思われる。l

781(○口○*)さん :06/05/07 17:25
pipe使えたのかー

てことは立ちアコみたいなアプリでホムを喋らせられるな
主人のクライアント上でしか認知できないが。

--[[
ログ保存系ツールと連携すれば主人の発言によるホムへの指示も可能か…
灰色…ログ保存のみなら白なのか?
--]]

782(○口○*)さん :06/05/07 19:25
pipeが潰される可能性を考えるとなかなか実用した後のフォローまで
回らないんじゃないか?

というか、クライアント以外に出力されると黒と取られる可能性の方が高いのでは?

783(○口○*)さん :06/05/07 23:58
とはいえ、あくまでROのプロセスには直接触らずに完全に独立したプログラムで、
やってる事は単にファイルに書き込んでるだけだからな〜。
PIPE_ACCESS_DUPLEX、PIPE_ACCESS_OUTBOUND とか使って
双方向通信してるとかだとまずいだろうけど。

・・・これでio関係が使えなくなったら俺のせいだな。 (;´ー`)y-~

784(○口○*)さん :06/05/08 00:06
クライアントと同時起動して、通常操作では出来ないことが出来るようになるのなら
思いっきり引っかかると思うな。過程がどうであれ。

785(○口○*)さん :06/05/08 07:29
ログ保存系ツールを使うと癌規約的に黒になってしまうから、
ケミ発言 -> /savechat でメッセージを取得できるようにすればいいんでない?

786(○口○*)さん :06/05/08 17:43
>>785
ログ保存は黒だったのか…

公式によると、
>運営チームが指定する以外の方法で画像や動画などを撮影することができるもの
と、あるが
チャットログも含まれてしまうって事か

チャットログは「通常のクライアントでは表示されないデータ」には当たらないと思ってたが
ダメだとすると夢が無いなぁ

是非ホムにチャットで指示したかった

787(○口○*)さん :06/05/08 18:07
>>786
>ラグナロクオンライン正規クライアント以外の外部プログラムを使用
>正規クライアントにはない機能を使ってゲームをプレイすることは禁止しています。

ログ自動保存は「正規クライアントにはない機能」に他ならないよね。

788(○口○*)さん :06/05/08 18:17
>>787
公式の不正ツールに関する記述は
タイマーや特にbotクライアントに言及してると思うが

ログ保存を自動化するくらいで拡大解釈して自己規制してしまうのは
ROらしいというか癌のユーザらしいというか。

本質的に不正となるかどうかと関係ないところが泣けてくる

789(○口○*)さん :06/05/08 18:23
とりあえずいろんなの作ってみて、個別に癌に「これおk?」って聞いてみて
「お答えできません」って回答をいただいて、「ダメって言われないんだからいいよね?」で
使いたい人だけ使えばよい。


                                 ………………………だめ?w

790(○口○*)さん :06/05/08 18:39
ハイド・クローク見破り外部ツールが一番黒い用途な気がする。

791(○口○*)さん :06/05/08 18:48
>>785
/savechat使わなくても、自分の発言を[Shift]+[DEL]でクリップボードにカットできるから
クリップボード→名前付きパイプに流し込むようなものを外部に用意すればよいかと。

792(○口○*)さん :06/05/08 18:52
普通にキーボード監視でいいじゃね?w

793(○口○*)さん :06/05/08 18:59
>>788
同意する
なんていうか本音と建前っつーか察しるのが下手っつーか・・・
まあ元は癌がちゃんとした線引きをしないまま放置した上に
最後は自爆から無差別規制って馬鹿やらかしたのが悪いんだが。

β1時代はGMに出来たツールをメールで送ったりして

「これは便利にご利用ですね(^ゝД*)」

などと珍奇な返答が返って来たりしてほのぼのしてたもんだがなあ
ちゃんと不味いもんは不味い言ってくれたしさ。

いじょうすれちがい

794(○口○*)さん :06/05/08 19:06
ひゃっくたん(つД`)

795(○口○*)さん :06/05/08 19:15
>>791
Shift+Delか
直前の発言をクリップボードに出せたのね

この方向でやってみるとするよ、実装も楽そうだし

796(○口○*)さん :06/05/08 19:16
>>793
上のと別の意味で泣いた。

797(○口○*)さん :06/05/08 19:21
>>788
黒は黒。

自分もログ自動保存は容認派とはいえ自主規制はまた別の話だし
スレ違いだからそれ以上はノーコメント。

798(○口○*)さん :06/05/08 19:50
実際に黒だとか白だとかが問題なのではない。

「黒と取れる可能性が少しでもある」場合、それを黒と捉えて
鬼の首を取ったように叩きに来る人物が現れる可能性があるから
面倒を回避するために自粛すべきだって言ってるんだ。

799(○口○*)さん :06/05/08 20:19
>>798
OK理解した。
変な話になってすまんかった。


SS加工問題とその炎上っぷりを思い出したよ…。

800(○口○*)さん :06/05/08 20:28
>>798の言う事は本質を突いてるな。
悲しい事だが、実際に黒であろうが無かろうが、
癌は声の大きい奴の言う事に合わせる事は、
今までROやってきた奴なら、身をもって判ってる。

有用な技術情報だけやりとりして、
実際の成果物はオープンしない方が良さそうだね。

801(○口○*)さん :06/05/11 01:02
ポポリン化したホムのIDとかってどうなってるのかね

802(○口○*)さん :06/05/11 06:12
IDってオブジェクトIDじゃなくてHOMUNTYPEのこと?
ステも見た目もポポリンになってるんだからポポそのものじゃないのかな。
あれは蘇生して変わったっていうけどシーズで殺してもやっぱりあのままなのだろうかなあ

803(○口○*)さん :06/05/12 23:02
ホムンクルスの攻撃速度が時々遅くなるのはなぜ??@@
ぜろまてさんのAI使用ですが、AIの関係なのかな?

804(○口○*)さん :06/05/12 23:17
空振ってんじゃねーの?

805(○口○*)さん :06/05/12 23:24
>>804
うちのほむHIT173で相手はバースリーなんですが@@;
HITが最大95%までっていうのも知ってますが>w<

806(○口○*)さん :06/05/12 23:29
遅くなってる間、トレース吐くとどういう動き方してるん?

807(○口○*)さん :06/05/12 23:34
今気が付いた。雑談・要望スレで聞いたほうがいいんじゃないか?

808(○口○*)さん :06/05/13 00:08
>>806
うぁ、スレ違いでしたか
失礼しました

809(○口○*)さん :06/05/13 01:10
スレ違いとまではいかないけど、あっちのほうが回答者の数が多そうだし、
どっちかというと向いてたから。

810(*○口○)さん :06/05/13 14:43
うなり、モアレ、言い方は色々あるけどAttackコマンドを送るAIの周期と
実際の攻撃速度とのズレが原因と、ラグが原因の2つかな
実際の攻撃速度が150msで、AIが160msなら2.4sに1回Attackコマンドが
送れない(攻撃しない)タイミングが出来る
ラグはおさss(ry

811(○口○*)さん :06/05/13 18:49
ちょっとでもASPDあげようと思ってやってみました。
はやくなった?ような気がする?そんくらいの効果でした。

function AI(myid)の先頭付近と終わり付近に

if (MyState == ATTACK_ST) then
OnATTACK_ST ()
end

これを追加してみただけ。これだと50m秒ごとくらいにOnATTACK_ST ()を実行してるんかね。

812(○口○*)さん :06/05/13 20:49
>>810みたいなのは低減されるかもしれないけど、
ATTACK_STの処理増やしてるとループ自体が重くなりそうだな…。
逆にそれ自体が軽めなら効果はそこそこだと思うけど。

813(○口○*)さん :06/05/16 09:36
あんまりネタは少ないがちょっと投下

最近気づいたのだが、AIのワンループ中ってGetTickとかGetActorsとか更新されていないみたいなんだけど
AIの最初にグローバル変数にぶち込んで、中でそのグローバル変数を使った方がいいのか、
毎回毎回ローカル変数にぶち込んだ方がいいのか
何がいいかなんてのは、処理速度でもいいしメモリ食わないとかでもいいのだが・・・

とりあえず話題になればと・・・・

814(○口○*)さん :06/05/16 13:35
それはただ単に値が変更するより早くループを抜けてるからじゃないかな?
AI()が呼ばれた瞬間のスナップショットを対象にすべての処理を行うって言うならそのほうが処理速度は速くなるはず

とここまで書いててふと思った
AIってクラから呼び出しによる同期実行だよな?
ってことはAIが走ってる間はクラの情報はまったく変わらないかも
AIからはクラの情報しか見れないし全部キャッシュしておけるかも知れない

ただ・・・150msに1度だけほんの数ms動くだけのAIにそこまでの最適化は求められていないかも

815(*○口○)さん :06/05/16 16:39
AIの先頭と終りのGetTickで差が見られないなら処理時間が1ms未満って事
単なる数値代入もforループで数十万回せば10ms程度は出る(含ループ処理
更に云億回とか処理を複雑にすると数秒クラが固まったりそのまま戻らない事も(Alt+F4

因みに>>811は約150msに1度、極めて短い間隔でAttackが2回になる
クラが2回共破棄せずにパケット送るかどうかは別問題だけどね(多分1回のみ

816(○口○*)さん :06/05/16 17:38
>>815
ありがとうございます
GetTickはこちらでも確認して来ました

GetActorsもそれでいけるかと思いましたが、
local s = 0
s = s + 1
s = s - 1
↑な計算を1000万回まわすループが、10回回ったくらいでフリーズしました
その間では、GetActorsについては、変化が観測できませんでした
1億回まわしたら、一回回るか回らないかでフリーズしてしまい観測できず・・・
マシンパワーなどもあるでしょうが、止まるか止まらないかのギリギリのラインが難しい・・・

817(○口○*)さん :06/05/16 17:39
>処理速度でもいいしメモリ食わないとかでもいい
Lua5.0.2のGCは確実だけどコストの高いMark & Sweep。
大きなテーブルを使い捨てで多用すると、GCを誘発して処理速度に影響を与える。

だからその観点から言えば、
tostring(GetActors()) == tostring(GetActors())
が偽(=呼び出し毎に別のtableが渡される)なら
GetActors()の多用はゴミを増やすことになるのであんまりよろしくない。
local actors = GetActors() -- ブロックを抜けたら燃えるゴミ

数値は即値でGC関係ないはずだから、GetTick()あたりは必要な時に呼んでいいと思う。

でもぶっちゃけ、GCのコストが気になる前にLua環境がまるごと破棄(再読込)される
ことが多いから、コーディングのしやすさを優先させて問題なさそう。

818(○口○*)さん :06/05/19 13:06
    く(
   /´。 `ー、   保守ぬるぽっぽ
  ヽ{  々 ゚l ノ
 (( ノ(    )ヽ ))
     ソソ

819(○口○*)さん :06/05/19 13:23
           ,..-─‐-..、
            /.: : : : : : : .ヽ
          R: : : :. : pq: :i}
           |:.i} : : : :_{: :.レ′
          ノr┴-<」: :j|
        /:r仁ニ= ノ:.ノ|!           _
          /:/ = /: :/ }!        |〕)  コツン
       {;ハ__,イ: :f  |       /´
       /     }rヘ ├--r─y/
     /     r'‐-| ├-┴〆      く(_  '⌒ ☆
      仁二ニ_‐-イ  | |        /´ 、 ヽ
      | l i  厂  ̄ニニ¬       ヽ{   々´l ノ
     ,ゝ、 \ \   __厂`ヽ    (( ノ(    )ヽ ))
     / /\_i⌒ト、_   ノrr- }       ソソ
   └-' ̄. |  |_二二._」」__ノ

820(○口○*)さん :06/05/19 14:05
オhムンクルス!
おまえの ひほうは かんぜんじゃないのさ!
ここに さいごのひほうがある!


    ∧
   /´。 `ーァ
   {  々 ゚l´ モグモグ
  / っ○o
 /    /
 ∪^∪

821(○口○*)さん :06/05/19 14:09
    l⌒l l⌒l
    |  |_|  |   / ̄ ̄ ̄ ̄ ̄ ̄
   / ・ ゚ ・ヽ < がおー
  ∪ヽ ̄ ̄ノ ⊃ \______
    |  ,二、 /
    ̄    ̄

822(○口○*)さん :06/05/19 16:07
保守ってほど間隔あいてるんだろうか。

ところで、ホム変化バグとやらは直ったのかねぇ?
怖くてAIデバッグできないのだが。

823(○口○*)さん :06/05/19 16:10
普通に治ってない

でも、ホム殺さなければとりあえずは問題ないと思われるのだが、殺さないといけない
デバッグなんだろうか?

824(○口○*)さん :06/05/19 16:38
>823
殺さないといけないデバッグってわけじゃぁ無いんですけどね
殺したmobが近所沸きしたら叩き続けようと特攻するのが直らないんで
その辺あたりを面倒見ようかと・・・

でも、めったに出ないから普通に狩り続けるしかないし、
そーなると死ぬかもしれないし・・・・・・

825(○口○*)さん :06/05/21 01:14
狩りでかなり頻繁に殺してるけど今のところはなんともないな
まあ怖いからあんまり殺さないようにはしてるし
枝テロとかオブジェクト多いときは出さないようにしてるけど

826(○口○*)さん :06/05/21 23:39
ちょっと確認させて欲しい
スキルや攻撃の射程内に入ったとき(発動したとき?)だけV_TARGETがセットさせるから
近接攻撃なら移動中は標的は不定ってことでいいのかな?

うちで組んだ限りでは上のようにはなってて近接するまでは反撃しないけど
もし違うとこあるなら教えてください

827(○口○*)さん :06/05/22 00:32
対象を取って効果発動または詠唱開始の2つがV_TARGETの設定される瞬間かな?
設定したあとはまた別な対象に対して攻撃するまで書き換わらない
リカバリでタゲ解除したりスタンで他の人をタゲっても実際に攻撃するまでは変わらない前の情報が残ってる

さらに言うならば攻撃をしたときではなく攻撃をしたのを見たとき。
画面外でいくら交戦してようが自分がそれを見ていなければターゲットは変わらない

828(○口○*)さん :06/05/22 10:04
>>826
そのとおり
>>827の言うように攻撃されるまで設定されない
相手が振りかぶったときと魔方陣が出た瞬間に設定
って事だから移動中はタゲなし

829826 :06/05/22 19:17
>>827,828
向かってくる移動中のアクティブも標的に認識させたいのだけどできなかったから
そこは自主的に向かわないといけないわけだね。
標的が更新されないのもちょっと面倒だなあ。
どうもありがとう。

830(○口○*)さん :06/05/24 03:03
AI初心者なんですが、ちょっと質問させてください。

今まで0マテさんのところのAIを使わせていただいていたのですが、
違うところのAIも試してみようかなということで、
PrivateMoonさんの所のこっこAIを試してみたんです。
とても使いやすいAIだったのですが、ちょっとだけ気になった点がありまして。

通常、主人が敵をクリックしたとき、敵の頭の上に小さな三角が出て、
クリックボタンを押したままだと自動で敵を殴り続けると思うのですが、
こっこAIを使っていると、クリックを押しっぱなしでも
主人が敵への攻撃をやめてしまうことがあるんです。
これが0マテさんのAIだとそういう現象は起きないようなのですが・・・。
何か原因があるのでしょうか?
もし分かる方がいれば、ぜひご教授ください。

831(○口○*)さん :06/05/24 09:05
>>830
作者に聞くのが一番じゃないか?

832(○口○*)さん :06/05/24 18:46
やめるタイミングは?
基本AIからはケミ動きには干渉出来ない
唯一スキルだけつかえるがな

833(○口○*)さん :06/05/24 19:00
>>830
どんな設計しても意図的にその現象を作ることが出来ないと思うんだけど…。
気のせいじゃない?

834(○口○*)さん :06/05/25 00:10
ホムスキル使うときに間違えてケミのID指定してあるとか

まぁないわな。こっこ持ってないからわからん

835(○口○*)さん :06/05/25 00:45
がーごたんはある日心優しいガーゴ族に拾われた子だと信じてる俺は異端らしい。

836(○口○*)さん :06/05/25 00:45
うはww誤爆wwwスマス

837(*○口○)さん :06/05/25 11:57
ASAHI-NET規制外れないなぁ・・・(´・ω・`)

*from5/23*
割と時間が掛かってしまいましたが、MAPデータを参照して
射線が通っているかどうかをチェックする関数を実装しました。
http://himenomikoto.at.infoseek.co.jp/kulus_project/index.html#MapReader.lua

移動に関してはそれっぽぃチェック方法は考えたのですが上手い具合にループが回せず苦戦中ですorz
回り込みを考えないのであれば射線判定をそのまま移動に組み込んで使っても問題はないです。

マップ指定用のhtaアプリはフィールドに使用する画像は出来たのですが、
ダンジョン用の画像が各ダンジョンの配置バランスが悪くて手間取ってます。
7月実装予定のタナトスタワーが1〜13階まであるのでそちらの配置も上手く出来る様にしたいけど・・・
//himenomikoto.at.infoseek.co.jp/kulus_project/test.png
何かいいレイアウトあったらお願いします_| ̄| ((○

あ、工体AIのcurrent_mapcode.lua形式にも対応出来る様にするので
完成したら工体AIのフィールド指定にも使えるようになりますですノシ

838830 :06/05/25 11:59
830です。
今、メイン狩場が西オーク村なんですが、廃オークが自分orホムを見つけて近づいてきますよね?
その時、近づいてくる敵にクリックし、そのままボタンを押し続けることが多いんです。
そうすると1〜2回殴った後、本人の自動攻撃が止まるんです。
と言っても、いつもというわけではなく、2匹に1回程度でしょうか・・・。
でも、クリックし直さないといけないのが面倒で結構気になるんですよね。
とりあえずこっこAIの作者さんの所にも連絡してみます。

839(○口○*)さん :06/05/25 12:00
たんに位置ずれ起こしてるとかじゃね?

840(○口○*)さん :06/05/25 12:34
こっこAIは関係ない可能性が高い

841(σ゚∀゚)σゲッツ!! ◆lz.qljqAls :06/05/25 13:53
>>837
GH以外のダンジョンは基本的に5階層まで(時計とかは地上と地下で分ければおk)だから
基本的には工体のところのやつみたいに横に並べていてタナトスタワーは13階までと長いから右端に縦に配置すればいいんじゃね?

仮に画面サイズを1024*768だとして1画面に収めたいなら
ttp://irischara.hp.infoseek.co.jp/test.png
こんな感じで階層が浅いものから並べてみればいいような気がする

ちなみに右端の空欄13個はタナトスタワー
ちょうどタワーという形式で縦に長い構造だから無理にばらすよりそのまま一列に配置でいいと思うよ

また新しいダンジョンが追加されればダンジョンの規模ごとに間に入れていけばいいし

842(○口○*)さん :06/05/25 15:24
>>837
おつかれさまです。

回り込み含めての移動可否チェックは、以前にこのスレで話題になったアルゴでいいんじゃないの?
ttp://tomose.dynalias.net/RO/index.php?AI%A5%E9%A5%A4%A5%D6%A5%E9%A5%EA
ここの Movelib。
オーバースペックと判断してもっと簡易なのを考えているなら別だけど。

843(○口○*)さん :06/05/25 19:42
とりあえず、完成したので晒してみます。
自前のAIとそのAI専用エディタ。
ttp://mmgguild.hp.infoseek.co.jp/lif0.zip

こゆのはどーなのかな…。

844(*○口○)さん :06/05/26 15:01
ASAHI-NET規s(ry

安直に階層=縦並びで並べてたけどやっぱ横の方がいいのかなぁ
//himenomikoto.at.infoseek.co.jp/kulus_project/test2.png


経路を細かく分けて移動出来るか?ではなくて、一度のMoveで移動出来るかを
返す関数を作りたかったんだけど現実問題、難しすぎたorz
勝手に迂回してくれる方が楽だろうしIsMovetoにちょぃ問題あるけど実用上は平気か・・・

IsMovetoの問題はテンキーで見て3→7を指定した時、
実際に移動できる為には3→5の時2か6どちらかが移動可で
5→7の時4か8のどちらかが移動可で無いといけないのに
357しかMAPチェックしていないから移動出来ない位置にtrueを返す
つまりは移動しない事が稀にある(限られた時だけだから滅多にない

845842 というかMoveEx()の人 :06/05/26 18:55
>>844
ああ、なるほど。
普通のMove()1発で行けるかどうか、って判定をしたいってことですね。
確かにそれができるなら、そのほうがわかりやすく&MoveEx()使わなくていけるんで楽チンだと思う。

わたしも少し考えたんだけど・・・やっぱりMove()そのものの迂回論理がわからないのが原因であきらめた口。
距離が近いと結構壁向こうとかでも回り込んじゃうくせに、
2点くらいの障害物でも引っかかるときがあるんだよね。
難しい。

IsMoveTo() の「斜め2点の壁をぬけちゃう」のは、わかっているけど放置している内容。
ご指摘の通り、あんまりそういう地点も少ないので、手間をケチってます(^^;

846(○口○*)さん :06/05/27 20:41
定期age

847(○口○*)さん :06/05/29 11:22
工体AIってもう更新停止したの?

848(○口○*)さん :06/05/29 14:43
いつ頃からか動作が怪しくなった(ML1でアクティブ化しなくなったり)
更新してないか結構頻繁に見に行ってたりするんだけどね。

849(○口○*)さん :06/05/29 17:15
工体のAI
良いんだけどもうちょっとスリムなやつが欲しいなぁ
なんかいろいろ機能付けすぎてやたらと膨らんでるし

850(○口○*)さん :06/05/29 20:28
過去のバージョン。おすすめ

851(○口○*)さん :06/05/30 07:32
りーふたんかわいいよりーふたん(*´Д`)ハァハァ

852(○口○*)さん :06/05/30 13:50
工体のAIは単純にマップ系が完了するまで更新してないだけなんじゃ?

マップ周りのやつがここ最近いろいろ変わったりしてるから落ち着くまで更新しないとかそんな感じだとおもってみたり