function OnAUTOEA_CMD_ST () -- フリットムーブレベル3を自動で使用 -- 1140行を参照
local casting = false local type = GetV(V_HOMUNTYPE, MyID)
if (type == FILIR or type == FILIR2 or type == FILIR_H or type == FILIR_H2) then if (EmergencyAvoidDelay == 0) then -- 初回 if (GetV(V_SP, MyID) == GetV(V_MAXSP, MyID) and (MyState ~= ATTACK_ST or MyState ~= IDLE_ST)) then -- SP満タン&非待機or攻撃時 EmergencyAvoidDelay = GetTick() + 50000 -- 次にかけ直すまでの時間(単位/ms) casting = true end else if (EmergencyAvoidDelay <= GetTick()) then -- 前回発動後一定時間経過 if (GetV(V_SP, MyID) == GetV(V_MAXSP, MyID) and (MyState ~= ATTACK_ST or MyState ~= IDLE_ST)) then -- SP満タン&非待機or攻撃時 EmergencyAvoidDelay = GetTick() + 5000 -- 次にかけ直すまでの時間(単位/ms) casting = true end end end
if (casting == true) then SkillObject(MyID, 3, IN_SKILL_EMERGENCYAVOID, MyID) -- フリットムーブレベル3使用 -- 使うスキルは1117行のスキルID参照 end
if (type == FILIR or type == FILIR2 or type == FILIR_H or type == FILIR_H2) then if (EmergencyAvoidDelay == 0) then -- 初回 if (GetV(V_SP, MyID) == GetV(V_MAXSP, MyID) and (MyState ~= ATTACK_ST or MyState ~= IDLE_ST)) then -- SP満タン&非待機or攻撃時 EmergencyAvoidDelay = GetTick() + 50000 -- 次にかけ直すまでの時間(単位/ms) casting = true end else if (EmergencyAvoidDelay <= GetTick()) then -- 前回発動後一定時間経過 if GetV(V_SP, MyID) >= 50 and (MyState ~= ATTACK_ST or MyState ~= IDLE_ST)) then -- SP満タン&非待機or攻撃時 EmergencyAvoidDelay = GetTick() + 5000 -- 次にかけ直すまでの時間(単位/ms) casting = true end end end
AIスレ4の92さんのものを採用しようと試みたのですが、 if (GetV(V_MOTION,v) ~= MOTION_DEAD) then が上手くいかないらしくて動かない… vの値ってMyEnemyのことを意味するのだろうか?? local actors = GetActors ()の次の行に加えるのかも未だに不明。
for i,v in ipairs(actors) do if (v ~= MyOwner and v ~= MyID) then -- ケミかホム自身じゃなければ if (GetV (V_TARGET,v) == MyOwner) then -- タゲがケミだったら if (IsMonster(v) == 1) then -- モンスターだったら ココ→ if (GetV(V_MOTION,v) ~= MOTION_DEAD) then -- 敵が死にモーションでなければ enemys[index] = v -- 敵のリストに追加 index = index+1 -- インデックスを1増やす end end end end end
TraceAI (string.format("AutoSkill : check %q(%d) Interval %d",v.name,v.id,GetTick() - v.time)) if true == v.trigger() and GetTick() - v.time > v.interval then TraceAI ("check true") ココ→ if GetV(V_MOTION,GetV(V_OWNER,MyID)) == MOTION_STAND and (v.user == nil or v.user == math.mod(GetV(V_HOMUNTYPE,MyID)-1,4)) +1 then U_AUTOSKILL[k].time = GetTick() to = assert(loadstring(v.to))() if type(v.lv) == "table" then for m,n in ipairs(v.lv) do if v.type == "Area" then
if (v ~= owner and v ~= myid) then -- ケミかホム自身じゃなければ target = GetV (V_TARGET,v) if (target == owner) then -- タゲがケミだったら if (IsMonster(v) == 1) then -- モンスターだったら ココ→ if (GetV(V_MOTION,v) ~= MOTION_DEAD) then -- 敵が死にモーションでなければ enemys[index] = v -- 敵のリストに追加 index = index+1 end else local motion = GetV(V_MOTION,i) if (motion == MOTION_ATTACK or motion == MOTION_ATTACK2) then enemys[index] = v index = index+1 end end end end
>>421 これでいい気がする。なんでホムのタイプ見るのに剰余なんかとってんだ if GetV(V_MOTION,GetV(V_OWNER,MyID)) == MOTION_STAND and (v.user == nil or v.user == GetV(V_HOMUNTYPE,MyID)) then
>>423が言ってるように+1の位置がおかしいからこうかな if GetV(V_MOTION,GetV(V_OWNER,MyID)) == MOTION_STAND and (v.user == nil or v.user == math.mod(GetV(V_HOMUNTYPE,MyID)-1,4)+1) then
function isOtherPlayer(myID) --他のプレイヤーがいる? local bResult = FALSE
local actors = GetActors () local ownerID = GetV (V_OWNER,myID) for i,v in ipairs(actors) do if (v ~= myID and v ~= ownerID) then -- 自分でもオーナーでもない if (IsMonster (v)<1) then -- 敵ではない bResult = TRUE break end end end return bResult end
という関数を作って 使いたいところで
if (isOtherPlayer(myID)) then -- 他にプレイヤーがいるときの処理. else -- 他にプレイヤーがいないときの処理. end
function checkStopContinualAttack (MyID,MyEnemy) -- タゲロスト? local motion= GetV(V_MOTION,MyEnemy) if (motion==-1 or motion==MOTION_DEAD) then return true end
-- タゲをもっていかれた? local target= GetV (V_TARGET,MyEnemy) if (target ~= MyID and target ~= GetV (V_OWNER,MyID) and target~=0) then return true end
>>500 取り敢えず浮かんだのが3つ 1.グローバル領域にMoveFlgみたいのを作って、 elseif (GetV(V_MOTION,MyID) == MOTION_STAND) then if (MoveFlg == 0) then MoveToOwner (MyID) MoveFlg = 1 とかやる(この場合移動完了した後にMoveFlg=0に戻す必要がある) 後ヒットストップに弱い
2.主人の移動を確認するまで動かない elseif (GetV(V_MOTION,MyID) == MOTION_STAND) then if (GetV(V_MOTION,GetV(V_OWNER,MyID)) == MOTION_MOVE) then MoveToOwner (MyID) 軽いけど、Gv中はいいが、通常時に遅れそうな予感
function AI(myid) local msg = GetMsg(myid) if msg == 1 then Move(myid,msg[2],msg[3]) end if msg == 7 then SkillObject(myid,msg[2],msg[3],msg[4]) end end
local x = GetPercentSP( MyID ) local a = (x^2-x*2) / 100 local r = math.random( 100 ) a = a * ( a / 100 ) TraceAI("Try Skill: a="..tostring(a).." r="..tostring(r).." sp="..tostring(x) ) if a > r and t() then if h == FILIR then -- AttackSightに入らなくてもスキルを撃つ SkillObject( MyID, Eval( Settings.SELF_SKILL_MOONLIGHT_LEVEL ), SKILL_MOONLIGHT, MyEnemy ) elseif h == VANILMIRTH then SkillObject( MyID, MAXLV_CAPRICE, SKILL_CAPRICE, MyEnemy ) end end
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
OnCHASE_STの適当なところに if(MySkill ~= 0 and GetDistance2(MyID,MyEnemy) < ("スキル用距離")) then if("スキルを使用するか否か、SP残量とかマスタが座ってるとか") then SkillObjedct(MyID,MySkillLevel,MySkill,MyEnemy) end end 試してないけど、こんなのでいけないかな? OnATTACK_STに入れば通常攻撃するわけだし
>>593 工体AIの自動スキル発動率は x = GetPercentSP( MyID ) a = (x^2-x*2) / 100 r = math.random( 100 ) a = a / count 上記で a > r のときスキルが発動します。式に直すと (SP(%)の2乗-SP(%)*2)/(100*その敵へのスキル試行回数) SPが10%のときには (10^2-10*2)/(100*試行回数)=0.8/スキル試行回数 となり乱数で0.8未満の数字が返ったとき、 つまり最大約0.8%の確率でスキルを使用するということになります。 ちょっと自信ないけどこんな感じかな
function EnePosi (id1,id2) local x1,y1 = GetV (V_POSITION,id1) local x2,y2 = GetV (V_POSITION,id2) local result = 0 if (x1 > x2) then -- id2がid1の西にいる result = result + 1 elseif (x1 < x2) then -- 東に result = result + 3 else result = result + 2 end if (y1 > y2) then -- 南に return result elseif (y1 < y2) then -- 北に result = result + 6 return result else result = result + 3 return result end end
>>647 自作なら、なにかトリガー(Alt+Tとか Alt+Tした後にマスタの一つ上のマスにX秒以内に移動させるとか) を作っておいて、 FriendList = {} function GetGMember() local actors = GetActors() for i,v in ipairs(actors) do if(vがプレーヤー and FriendListにvが登録されていない)then FriendListにvを登録 end end FriendListをファイルに書き出す end こんなんじゃダメかな? 後はファイルをロードすればそのとき登録したメンバーは、いつでも使える その代わり、関係ないキャラが範囲内に居た場合も登録しちゃうけどね
for i,v in ipairs(actors) do if (v == owner ) then target = GetV (V_TARGET,v) if (IsMonster(target) == 1) then enemys[index] = target index = index+1 end elseif (v ~= owner and v ~= myid and MOTION_DEAD ~= GetV(V_MOTION,v)) then target = GetV (V_TARGET,v) if (target == owner) then if (IsMonster(v) == 1) then enemys[index] = v index = index+1 else local motion = GetV(V_MOTION,v) if (motion == MOTION_ATTACK or motion == MOTION_ATTACK2) then enemys[index] = v index = index+1 end end end end end
などのパターンもあったりで色々とAIをいじくってみたものの プログラムの式は間違ってはいない感じ…なのかな どうやら挿入してる場所がおかしいのかもしれない…のかな(´・ω・`) ちなみにこんな感じです。 … function OnATTACK_ST ()
-- 桃木が同画面に横沸きした場合に殴りかからない(横殴り防止) local x, y = GetV (V_POSITION,MyEnemy) if (MyDestX ~= x or MyDestY ~= y) then type = GetV (V_HOMUNTYPE,MyEnemy) if (type == 1410) then -- 桃木の場合に限り MyEnemy = 0 end end
>攻撃中の敵の座標が変わったら if (MyDestX ~= x or MyDestY ~= y) then OKっぽいんだけどMyDestX,Yってどこで設定したものを使ってる? 本当に敵の座標が入っている? デフォだと移動目標だから主人の座標が入っていることも右クリックした座標が入っていることもある 敵が前回居た場所を見るならグローバル変数とかにMyEnemyX、MyEnemyYを追加して OnATTACK_STの最後で設定するのがいいかな
>>669 根底から覆すようであれなんだけど local target = GetV(V_TARGET,MyEnemy) if target ~= 0 and target ~= MyID and target ~= GetV(V_OWNER,MyID) then MyEnemy = 0 MyState = IDLE_ST return end 自分たち以外の誰かを狙ってたら攻撃止め 横殴り対策だけならこれじゃいかんの?
>>695 -- 桃木が同画面に横沸きした場合に殴りかからない(横殴り防止) local type = GetV (V_HOMUNTYPE,MyEnemy) if (type == 1410) then -- 桃木の場合に限り if (MyEnemyX == 0 and MyEnemyY == 0) then MyEnemyX, MyEnemyY = GetV (V_POSITION,MyEnemy) else local x, y = GetV (V_POSITION,MyEnemy) if (MyEnemyX ~= x or MyEnemyY ~= y) then MyEnemy, MyEnemyX, MyEnemyY = 0, 0, 0 MyState = IDLE_ST return end MyEnemyX, MyEnemyY = x, y end end
local target = GetV(V_TARGET,MyEnemy) if target ~= 0 and target ~= MyID and target ~= GetV(V_OWNER,MyID) then local x,y = GetV(V_POSITION,id) if x == -1 then MyEnemy = 0 MyState = IDLE_ST return end end
>>718の部分にバグ発見! 元のAIで1019行目 if (GetV(V_MOTION,v) ~= MOTION_DEAD) then -- 敵が死にモーションでなければ ↓ if (GetV(V_MOTION,target) ~= MOTION_DEAD) then -- 敵が死にモーションでなければ 上のじゃ「主人が死にモーション」になってる
if USEWALLMODE == 1 then ReadyWallMode = 1 FinishedAttackFlag = 0 end
OnATTACK_ST()関数内の以下の部分を変更
if (MySkill == 0) then Attack(MyID, MyEnemy) --←この部分を(1行) else
↓
if (MySkill == 0) then if FinishedAttackFlag == 0 then Attack(MyID, MyEnemy) end -- ←このように if ReadyWallMode == 1 then FinishedAttackFlag = 1 end -- ←変更する(2行) else
>>734 の2038〜2046行目 --------------------------------------------------------------------------------- if (MyState == IDLE_ST) then OnIDLE_ST () -- 待機状態の処理 elseif (MyState == CHASE_ST) then OnCHASE_ST () -- ターゲット追跡状態の処理 elseif (MyState == ATTACK_ST) then OnATTACK_ST () -- ターゲット攻撃状態の処理 elseif (MyState == FOLLOW_ST) then OnFOLLOW_ST () -- ケミ追従状態の処理 elseif (MyState == ATTACK_OBJECT_CMD_ST) then --------------------------------------------------------------------------------- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --------------------------------------------------------------------------------- if (MyState == IDLE_ST) then OnIDLE_ST () -- 待機状態の処理 end if (MyState == CHASE_ST) then OnCHASE_ST () -- ターゲット追跡状態の処理 end if (MyState == ATTACK_ST) then OnATTACK_ST () -- ターゲット攻撃状態の処理 end if (MyState == FOLLOW_ST) then OnFOLLOW_ST () -- ケミ追従状態の処理 end if (MyState == ATTACK_OBJECT_CMD_ST) then --------------------------------------------------------------------------------- 倒した後とか策敵1回やった後MyStateが変わっても 次にAI()が呼ばれる150ms後まで実際の移動や攻撃を開始しないせいだ 0マテなんかは1度状態が変わったら状態が変わった後の処理を次の判定で開始する。
if (FlagIgnorePlantMob == YES and ignoreflag == NO) then -- ■ケミ召喚植物を無視する設定が有効であれば MobID = GetV(V_HOMUNTYPE,v) -- ■敵の種類を取得して if (MobID == 1589 or MobID == 1579 or MobID == 1575 or MobID == 1555 or MobID == 1590 or MobID == 1142) then -- ■敵がケミ召喚植物であれば ignoreflag = YES -- ■無視フラグをYESに else -- ■敵がケミ召喚植物で無ければ ignoreflag = NO -- ■無視フラグをNOに end end
if (v ~= owner and v ~= myid) then -- オブジェクトがケミとホム自身じゃない場合 if (1 == IsMonster(v) and ignoreflag == NO) then -- ■オブジェクトがモンスターで、無視フラグがNOであれば、 enemys[index] = v -- ■無条件で敵の配列にオブジェクトを追加し index = index+1 -- ■敵の配列をインクリメント end end
local x , y = GetV (V_POSITION,MyEnemy) local myX, myY = GetV (V_POSITION,MyID) if (math.abs(x-myX)>2 and math.abs(y-myY)>2) then MyState = IDLE_ST TraceAI ("ATTACK_ST -> IDLE_ST") return end
>806 アルケミのAIを語るスレ2の625の奴じゃダメかね? function GetMyEnemyB (myid)を書き換える奴
for i,v in ipairs(actors) do if (v ~= owner and v ~= myid ) then if (1 == IsMonster(v) and IsNotNoManner( myid, v )) then if (5 >= GetDistance2 (GetV(V_OWNER,MyID), v)) then enemys[index] = v index = index+1 end end end end
工体AIだね function IsNotNoManner( myid, id ) local target = GetV( V_TARGET, id ) return target == 0 or ( target == myid or target == GetV( V_OWNER, myid ) ) end だそうだ(本家より転載) 誰か他の人を狙ってなければって感じかな
function OnSKILL_OBJECT_CMD (level,skill,id) SkillObject (MyID,level,skill,id) end 俺が使ってるのはこれ スキル使うって言ったらスキル使うだけ。 余計なことはしてくれるな。とね 一部の状態だけって定義したいなら条件分岐でも切ればいい
ぁ ちゃんと帰ってきてたんだw それなら functionOnSKILL_OBJECT_CMD (level,skill,id) if GetDistance2(id,MyID) <= GetV(V_SKILLATTACKRANGE,MyID,skill) then SkillObject (MyID,level,skill,id) end end でいいね。
function CheckMove() if MyDestX == 0 and MyDestY == 0 then return end local myX,myY = GetV(V_POSITION,MyID) if myX == MyDestX and myY == MyDestY then MyDestX,MyDestY,MyStop = 0,0,0 elseif myX == MyLastX and myY == MyLastY and GetV(V_MOTION,MyID) ~= MOTION_MOVE then MyStop = MyStop + 1 if (MyStop > 5) then MyStop = 0 Move(MyID,MyDestX,MyDestY) end else MyStop = 0 end MyLastX,MyLastY = myX,myY end
OnATTACK_ST()時重力座標にハマって攻撃出来なくなる現象 敵との距離がクラ上では2マスだが鯖上で3マスなんかになってOnATTACK_ST()のままOnCHASE_ST()に戻る事も出来ない状態 OnATTACK_ST()で設定さてたオートカプリスは発動しつづけるのでクラ上通常攻撃射程内にいて、AIもそれを受け取って スタックしてる模様、なので 一定時間攻撃モーションが帰ってこなかったら自分の座標を中心に東西南北へ移動する関数を作ってみたが if (AttackFailTime == 0 or GetV(V_MOTION,MyID) == MOTION_ATTACK or GetV(V_MOTION,MyID) == MOTION_ATTACK2) then AttackFailTime = GetTick() end if (GetTick() - AttackFailTime > 2000) then Secession ()-- 現在座標を移動する AttackFailTime = 0 else AttackFailTime = 0 end だと、スタックしても移動してくれず if (AttackFailTime == 0 or GetV(V_MOTION,MyID) == MOTION_ATTACK or GetV(V_MOTION,MyID) == MOTION_ATTACK2) then AttackFailTime = GetTick() end if (GetTick() - AttackFailTime > 2000) then Secession ()-- 現在座標を移動する AttackFailTime = 0 end だと、スタックの有無に関係なく時間が来たら移動してしまう なんとか良い方法はないでしょうか?