function OnSKILL_OBJECT_CMD (level,skill,id) TraceAI ("OnSKILL_OBJECT_CMD") if (level == 1 and skill == 8009) then --Lv1ムーンライトが使われたら local enemy = 0 local loop = 0 while (loop == 0) do enemy = GetActor() for i,v in ipiars(enemy) do --敵が周囲から見つからなくなったらループ脱出 if (v == id) then loop = 1 break end end SkillObject(MyID,1,(メマー),MyID) --メマー撃つ end return end end
if (MyEnemy_Type == 1) then -- 非先行型だと判断できた場合 result = GetMyEnemyA (myid) -- 非先行型 elseif (MyEnemy_Type == 0) then -- 先行型だと判断できた場合 if(Generation_Time + 10000 < GetTick()) then -- 先行型でも最初の10秒は非先行型と同じ処理 result = GetMyEnemyB (myid) -- 先行型 else result = GetMyEnemyA (myid) end end return result end
MyID = myid local msg = GetMsg (myid) -- command local rmsg = GetResMsg (myid) -- reserved command
--※此処から追加
if (type == LIF or type == LIF2 or type == LIF_H or type == LIF_H2) then if (msg[1] == FOLLOW_ST) then if ( MyActivHealCount > 0 ) then OnSKILL_ACT_HEAL_ST () --手動ヒール end MyActivHealCount = HEAL_IDLE_TIME end
--手動ヒール function OnSKILL_ACT_HEAL_ST() local result = false local owner = GetV (V_OWNER,MyID) local actors = GetActors () local heal_target = {} local index = 1 local type for i,v in ipairs(actors) do if (v ~= owner and v ~= MyID) then if (1 ~= IsMonster(v)) then heal_target[index] = v index = index+1 end end TraceAI ("roop_number = ") TraceAI ( i ) end local min_dis = 3 local dis local target_counter for i,v in ipairs(heal_target) do dis = GetDistance2 (MyID,v) if (dis < min_dis) then result = true min_dis = dis target_counter = v end end if ( result ) then if ( target_counter ~= nll) then TraceAI ("ACTIV_HEAL_USE") SkillObject(MyID, ACTIV_HEAL_LEVEL, SKILL_TOUCH_OF_HEAL, target_counter) -- ヒール使用 end else TraceAI ("ACTIV_HEAL_FAIL") end end
for k,v in ipairs(U_AUTOSKILL) do --定義された自動使用スキルを1つずつチェック TraceAI (string.format("AutoSkill : check %q(%d)",v.name,v.id)) if GetTick() - v.time > v.interval and true == v.trigger() then TraceAI ("check true") U_AUTOSKILL[k].time = GetTick() --タイマ更新 to = assert(loadstring(v.to))() --to読み出し if type(v.lv) == "table" then --lvが配列なら順次実行 for m,n in ipairs(v.lv) do SkillObject (MyID,n,v.id,to) TraceAI (string.format("SkillObject(%d,%d,%d,%d)",MyID,n,v.id,to)) end else SkillObject (MyID,v.lv,v.id,to) TraceAI (string.format("SkillObject(%d,%d,%d,%d)",MyID,v.lv,v.id,to)) end else TraceAI ("check false") end end end
そしてfunction AI(myid)の中で呼び出す。
if GetTick() - last > 1000 then -- 1秒間隔で自動スキルチェック AutoSkill_CMD () last = GetTick() end
>106 確かに…ホムを変える事を考えてなかったから気付かなかった。他にも色々修正してみた。 function AutoSkill_CMD () -- 汎用スキル自動使用関数 for k,v in ipairs(U_AUTOSKILL) do TraceAI (string.format("AutoSkill : check %q(%d)",v.name,v.id)) TraceAI (string.format("Interval : %d",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)) < 3 and (v.user == nil or v.user == math.mod(GetV(V_HOMUNTYPE,MyID)),4)) then --本体がスキル使用可能 かつ ホムの系統がuserとマッチした時 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 SkillGround (MyID,n,v.id,to) TraceAI (string.format("SkillGround(%d,%d,%d,%d)",MyID,n,v.id,to)) else SkillObject (MyID,n,v.id,to) TraceAI (string.format("SkillObject(%d,%d,%d,%d)",MyID,n,v.id,to)) end end else if v.type == "Area" then SkillGround (MyID,v.lv,v.id,to) TraceAI (string.format("SkillGround(%d,%d,%d,%d)",MyID,v.lv,v.id,to)) else SkillObject (MyID,v.lv,v.id,to) TraceAI (string.format("SkillObject(%d,%d,%d,%d)",MyID,v.lv,v.id,to)) end end else TraceAI ("Skill isn't in use.") end else TraceAI ("check false") end end end
U_AUTOSKILL = { { name = "Rest", id = 244, lv = 1, to = "return MyID", interval = 120000, time = GetTick(), type = "Obj", user = nil, --ケミスキルならnil trigger = function() local x,y = GetV(V_POSITION,MyID) if x2 ~= nil and y2 ~= nil and (x ~= x2 or y ~= y2) then x2,y2 = x,y U_AUTOSKILL[k].time = GetTick() --座標が書き換わった時、タイマ更新 return false else return true end end }, { name = "EmergencyAvoid", id = 8002, lv = 3, to = "return MyID", interval = 35000, type = "Obj", time = 0, user = LIF, --使用するホムの系統 trigger = function() return true end }, }
local ownerTarget ownerTarget = GetV(V_TARGET, GetV(V_OWNER, MyID)) -- ケミのタゲを取得 if 0 ~= ownerTarget then if ownerTarget ~= GetV(V_OWNER,MyID) then -- タゲがケミ自身でなければ local targetX, targetY targetX, targetY = GetV (V_POSITION, ownerTarget) Move (MyID, targetX, targetY-1) -- 対象の1セル下へ移動 return end end
---------------------------------------- -- 移動コマンド ---------------------------------------- function OnMOVE_CMD (x,y)
TraceAI ("OnMOVE_CMD")
if ( x == MyDestX and y == MyDestY and MOTION_MOVE == GetV(V_MOTION,MyID)) then return -- 目的地と現在地が同一の場合は、処理しない end
local curX, curY = GetV (V_POSITION,MyID) if (math.abs(x-curX)+math.abs(y-curY) > 15) then -- 目的地が一定距離以上なら (サーバーで遠距離は処理しないため) List.pushleft (ResCmdList,{MOVE_CMD,x,y}) -- 元の目的地への移動を予約する x = math.floor((x+curX)/2) -- 中間地点へ移動する y = math.floor((y+curY)/2) -- end
if(type == AMISTR or type == AMISTR_H or type == AMISTR2 or type == AMISTR_H2) then -- ホムが羊の場合 local mysp = GetV (V_SP,myid) -- 自分のSPを格納 local tick = GetTick() -- 時間を取得
if(mysp >= 30 and tick > Defence) then Defence = tick + 40000 -- スキルタイマーのセット DelayCount = tick + 40000 -- 持続時間中はずっとディレイタイム SkillObject(myid, 1, 8006, myid) return 1 end
for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then local type = GetV(V_HOMUNTYPE,v) -- 対象がPCである場合他PCリストに追加 if (0 <= type or type <= 23 or 4021 <= type or type<= 4046) then others[indexo] = v indexo = indexo+1 end end end for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then local target = GetV (V_TARGET,v) if (target == myid) then local motion = GetV(V_MOTION,v) if (motion == MOTION_ATTACK or motion == MOTION_ATTACK2) then enemysA[indexA] = v indexA = indexA+1 end
elseif (1 == IsMonster(v))then monster = v local check = false for i,v in ipairs(others) do if (false == check) then if (GetV (V_TARGET,MyOwner) == monster) and ((GetV(V_MOTION,MyOwner) == MOTION_ATTACK or GetV(V_MOTION,MyOwner) == MOTION_ATTACK2)) then enemysB[indexB] = monster indexB = indexB+1 check = true elseif (GetV (V_TARGET,v) ~= monster) and (GetV(V_TARGET,monster) ~= v) and (GetDistance2 (monster, v) > 4) then enemysB[indexB] = monster indexB = indexB+1 check =true end end end end end end
if (indexA >1) then local min_dis = 100 local dis for i,v in ipairs(enemysA) do dis = GetDistance2 (myid,v) if (dis < min_dis) then result = v min_dis = dis end end else local min_dis = 11 local dis for i,v in ipairs(enemysB) do dis = GetDistance2 (myid,v) if (dis < min_dis) then result = v min_dis = dis end end end return result end
function OnFOLLOW_ST ()ホムが遅れないように弄りたいのですが ./AI/USER_AI/AIlua:681 attempt toperform arithmetic on global `MoveTimeDeley(a nil value) というエラーが、歩くたびに出ます エラーはOK押したらそれで終わるのですが歩くたびにエラーが出て・・・
>>雑談スレ68 local ownermotion = GetV(V_MOTION,owner) --主人のモーションを取得 if(ownermotion == MOTION_ATTACK or ownermotion == MOTION_ATTACK2) then --主人が攻撃中なら result = GetV(V_TARGET,owner)--resultを主人の攻撃対象に end function GetOwnerEnemy (myid)ブロックの終わりのほうにあるreturn resultの前に↑をを書き足す resultをMyEnemyに変えてOnATTACK_ST()内の最初に書けばホムが別の敵を攻撃中でも主人が殴ってる敵にタゲを変えるようになる 動作未確認
---------------------------------------------------------------------- -- ケミから少し離れる ---------------------------------------------------------------------- function RemoveFromOwner() -- ここにケミから少し離れる処理を書く local x, y = GetV(V_POSITION, MyID) if FlgRemove==false then local radian = GetSafeDirection() --*1 local dx, dy = math.floor(REMOVEDISTANCE*math.cos(radian)), math.floor(REMOVEDISTANCE*math.sin(radian)) MyRemoveX, MyRemoveY = x+dx, y+dy Move(MyID, MyRemoveX, MyRemoveY) FlgRemove=true end Count = Count+1 if x==MyRemoveX and y==MyRemoveY or Count>15 then FlgRemove = false Count = 0 return true end return false end ---------------------------------------------------------------------- *1 移動する方向を求める関数。
---------------------------------------------------------------------- -- GetSafeDirection() -- 最も安全な方向を取得する -- 戻り値 -- 安全な方向をラジアン値で返す -- 東を0とし、反時計回りをプラスとする -- この関数では値の範囲は0〜2πとなる ---------------------------------------------------------------------- function GetSafeDirection() local result = 0 local actors = GetActors() local radian = 0 local atk, atk_x, atk_y = 0, 0, 0
for i, v in ipairs(actors) do --周りのID全てを処理 if IsActiveMonster(v) then --IDがアクティブモンスターならば *2 radian = GetRadian2(MyID, v) --ホムから見た角度を取得 *3 atk = GetMobData(M_V_ATKMAX, id) --MobのAtkを取得 *4 if atk~=nil then --Atkが取得できたら atk_x = atk_x + atk * math.cos(radian) --AtkをX方向へ分解 atk_y = atk_y + atk * math.sin(radian) --AtkをY方向へ分解 それぞれ足していく end end end if atk_x==0 and atk_y==0 then --敵Atk分布が一様なら result = GetRadian2(MyID, MyOwner) --ケミの方向を危険とする if result==nil then --ケミと同一座標なら result = 0 --東を危険とする end else --分布に偏りがあれば result = math.atan2(atk_y, atk_x) --分布が濃い方向が危険 end result = result + math.pi --反対方向を安全とする return result end ----------------------------------------------------------------------
-- ここから -- 初撃必ずランダムボルト function FirstAttackCaprice(level, usesp, spPer)
-- 既に使った if CapriceFlag == 1 then return end
-- SP足りないので終了 if (GetV(V_SP, MyID) < usesp) then return end
-- 一定率以上SPないと使用しない local sp = GetV(V_SP, MyID) local msp = GetV(V_MAXSP, MyID) if ((sp / msp) * 100) < spPer then return end
local type = GetV(V_HOMUNTYPE, MyID)
if (type == VANILMIRTH or type == VANILMIRTH2 or type == VANILMIRTH_H or type == VANILMIRTH_H2) then local skillCaprice = 8013 SkillObject(MyID, level, skillCaprice, MyEnemy) CapriceFlag = 1 end
-- id:対象モンスター function CanAttack( id ) local actors = GetActors() -- IDがタゲってる敵を取得 -- 何かをタゲっていてそれがホムでもマスターでもない if( GetV( V_TARGET , id ) ~= 0 and GetV( V_TARGET , id ) ~= ホムID and GetV( V_TARGET , id ) ~= ケミID ) then return 1 end
for i , v in ipairs( actors ) do if( IsMonster( v ) ~= 1 ) then if( GetV( V_TARGET , v ) == id ) then return 1 end else end end
local eTarget = GetV( V_TARGET , id ) if( eTarget == 0 ) then return 0 end if( eTarget == ホムID or eTarget == ケミID ) then return 0 end return 1 end
ちょいと質問よいですか? 現在以下の様にフリットムーブを使っているのですが FleetMoveDelay = 0 function OnAutoSkill_CMD_ST () Skilllevel = 1-- 使用するスキルレベル SPEmpty = 30-- 使用後SPがこの%以下になる場合は使用しない IN_SKILL_FLEETMOVE = 8010 FMSPGain = 20 + (Skilllevel * 10)--消費SP FMSkillLimittime = 65000 - (Skilllevel * 5000)--持続時間 local casting = false local type = GetV(V_HOMUNTYPE, MyID) local HomunculusSP = GetV (V_SP,MyID) local HomunculusMaxSP = GetV (V_MAXSP,MyID) if (type == FILIR or type == FIRIR2 or type == FILIR_H or type == FILIR_H2) then if HomunculusSP < FMSPGain then return end if (FleetMoveDelay == 0) then if (SPEmpty < ((HomunculusSP - FMSPGain) / HomunculusMaxSP)*100) then FleetMoveDelay = GetTick() + FMSkillLimittime casting = true end else if (FleetMoveDelay <= GetTick()) then if (SPEmpty < ((HomunculusSP - FMSPGain) / HomunculusMaxSP)*100) then FleetMoveDelay = GetTick() + FMSkillLimittime casting = true end end end if (casting == true) then SkillObject(MyID, Skilllevel, IN_SKILL_FLEETMOVE, MyID) end end end
条件が重なるってのが良くわからないのですが OnIDLE_ST ()内で、こんな↓かんじで呼んだらいいのと違う? /**********************************************************/ if (FleetMoveDelay < GetTick()) then OnAutoSkill_CMD_ST () elseif (OverSpeedDelay < GetTick()) then OnAutoSkill2_CMD_ST () end /**********************************************************/
function GetMyEnemyB (myid) の中の if (1 == IsMonster(v)) then という行を if (1 == IsMonster(v) and GetDistance2(owner, v) <= 14-2) then に変更するといけそうです。 草とかで簡単に試せます。
9は検知無し、拾う、投げる等は殆ど一瞬、死ぬに居たっては直後にAIが終了するので本当に↓の様な物で無いと難しい function AI (myid) fp = io.open("AI/USER_AI/motion.txt", "a") if(fp == nil) then return end Ty = GetV(V_MOTION,id) fp:write( string.format("%s\n", Ty) ) fp:close() end
if ((GetV(V_SP,MyID)/GetV(V_MAXSP,MyID))*100 >= 20)then local x, y = GetV (V_POSITION,MyEnemy) if (MyDestX ~= x or MyDestY ~= y) then -- DESTCHANGED_IN MyDestX, MyDestY = GetV (V_POSITION,MyEnemy); local ax,ay = GetV(V_POSITION,MyID) if (MyDestX < ax) then MyDestX = MyDestX+3 elseif (MyDestX > ax) then MyDestX = MyDestX-3 end if (MyDestY < ay) then MyDestY = MyDestY+3 elseif (MyDestY > ay) then MyDestY = MyDestY-3 end Move (MyID,MyDestX,MyDestY) TraceAI ("CHASE_ST -> CHASE_ST : DESTCHANGED_IN") return end SKILL_CAPRICE = 8013 SKILL_USELEVEL = 5 SkillObject (MyID,SKILL_USELEVEL,SKILL_CAPRICE,MyEnemy)--スキル使用 end を元のlocal x, y = GetV (V_POSITION,MyEnemy)の前に追加してみました 3セル前までは行くのですが、その後スキルを使ってくれずそのまま追いかけてしまいますorz 原因はなんなのでしょう?
でもっておいらも小物関数を晒してみる -------------------------------------------------------------------------------- -- idがリーフかどうかを返す -- リーフならtrueを違うならfalseを返す -------------------------------------------------------------------------------- function IsLif( id ) local type = GetV( V_HOMUNTYPE, id ) if( type == LIF or type == LIF_H or type == LIF2 or type == LIF_H2 ) then return true end return false end -------------------------------------------------------------------------------- -- idがアミストルかどうかを返す -- アミストルならtrueを違うならfalseを返す -------------------------------------------------------------------------------- function IsAmistr( id ) local type = GetV( V_HOMUNTYPE, id ) if( type == AMISTR or type == AMISTR2 or type == AMISTR_H or type == AMISTR_H2 ) then return true end return false end -------------------------------------------------------------------------------- -- idがフィーリルかどうかを返す -- フィーリルならtrueを違うならfalseを返す -------------------------------------------------------------------------------- function IsFiril( id ) local type = GetV( V_HOMUNTYPE, id ) if( type == FILIR or type == FILIR2 or type == FILIR_H or type == FILIR_H2 ) then return true end return false end -------------------------------------------------------------------------------- -- idがバニルミルトかどうかを返す -- バニルミルトならtrueを違うならfalseを返す -------------------------------------------------------------------------------- function IsVanilmirth( id ) local type = GetV( V_HOMUNTYPE, id ) if( type == VANILMIRTH or type == VANILMIRTH2 or type == VANILMIRTH_H or type == VANILMIRTH_H2 ) then return true end return false end
その2 -------------------------------------------------------------------------------- -- 囲まれ人数を返す -- id はホムのid -- 戻り値は囲まれているMob数 -------------------------------------------------------------------------------- function GetBoxNum( id ) local owner = GetV( V_OWNER, id ) local actors = GetActors () -- 周りのキャラクターidを全部取得 local index = 0 for i, v in ipairs( actors ) do -- 敵をピックアップ if( v ~= id and v ~= owner and IsMonster( v ) == 1 ) then -- オーナーかホムをタゲっているものは敵 local target = GetV( V_TARGET, v ) if( target == id or target == owner ) then index = index + 1 end end end return index end
-------------------------------------------------------------------------------- -- id1から見たid2の方向(角度)を得る -- 戻り値:0〜359(右方向=0度、上方向=90、左方向=180度、下方向=270) -------------------------------------------------------------------------------- function GetDegree( id1, id2 ) local x1, y1 = GetV( V_POSITION, id1 ) local x2, y2 = GetV( V_POSITION, id2 ) local degrees = math.deg( math.atan2( y2 - y1, x2 - x1 ) ) if( degrees < 0) then degrees = 360 + degrees end return degrees end
--*****************プレイヤーID入手用ルーチン*********************** function GetPlayers (myid) local result = 0 local PCowner = GetV (V_OWNER,myid) local PCactors = GetActors () local PCPlayers = {} local PCindex = 1
for PCi,PCv in ipairs(PCactors) do if (PCv ~= PCowner and PCv ~= myid) then if (IsMonster(PCv) == 0) then PCPlayers[PCindex] = PCv PCindex = PCindex+1 end end end
local min_PCdis = 50 --ここの数値を変えるとプレイヤーキャラに対する反応距離が変わる(はず) local PCdis for PCi,PCv in ipairs(PCPlayers) do PCdis = GetDistance2 (myid,PCv) if (PCdis < min_PCdis) then result = PCv min_PCdis = PCdis end end return result end
IsInAttackSightの if (MySkill == 0) then a = GetV (V_ATTACKRANGE,id1) else a = GetV (V_SKILLATTACKRANGE,id1,MySkill) end を if (MySkill == 0) then a = GetV (V_ATTACKRANGE,id1) else a = 100 end に変えちゃえば手動使用では遠距離スキルに早代わりするね
local target = GetV(V_HOMUNTYPE,TargetID) -- MOBのIDを取得 if(target == 1002 or target == 1031or target == 1131 or target == 1051) then ) then -- もし、ターゲットがポリンかポポリンかドロップスか盗蟲だったら result = v --攻撃する
簡単にいじるならこんな感じ? local target = GetV(V_HOMUNTYPE,MyEnemy) -- MOBのIDを取得 local result = False if(target == 1002 or target == 1031or target == 1131 or target == 1051) then --略 result = true --true攻撃する end
以下の関数をどっか適当に記述。 ----------------------ここから--------------- function HomSTOPCHK ()
local x, y = GetV (V_POSITION,MyID) -- ホムの現在座標を取得 if (x == x2 and y == y2) then -- 停止している if(StopTime ==0) then -- 停止し始めた時間が取得されてないなら StopTime = GetTick() -- 停止し始めた時間を取得 end if((StopTime+StopLimit) < GetTick()) then -- 停止時間が長いようであれば TraceAI ("停止時間が長いので移動をキャンセルしました") MyState = IDLE_ST -- ホム状態を待機状態にする end else StopTime = 0 end x2, y2 = GetV (V_POSITION,MyID) -- ホムの現在座標を停止判定用に取得 end
今のところ2パターンで悩んでる function GetMyEnemy (myid) local result = 0
local mobact = MOBDATA[id][M_V_ACT] --行動を取得 if (mobactid == 0) then result = GetMyEnemyA (myid) --0ならば攻撃しない elseif (mobactid == 1)then result =GetMyEnemyB (myid) --1ならば攻撃する end return result end
function OnFOLLOW_CMD_ST () TraceAI ("OnFOLLOW_CMD_ST") 〜〜略〜〜 end end を function OnFOLLOW_CMD_ST () local ownerX, ownerY ownerX, ownerY = GetV (V_POSITION,GetV(V_OWNER,MyID)) if (ownerX ~= MyOwnerX or ownerY ~= MyOwnerY) then MyOwnerX = ownerX MyOwnerY = ownerY MyState = IDLE_ST end return end に変更
function GetMyEnemyB (myid) local result = 0 local owner = GetV (V_OWNER,myid) local actors = GetActors () local enemys = {} local index = 1 local type 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 end end end
local min_dis = 100 local dis for i,v in ipairs(enemys) do dis = GetDistance2 (myid,v) if (dis < min_dis) then local mobact = MOBDATE[id][M_V_ACT] -- モンスター名称取得 if (mobact == 1) then result = v min_dis = dis end end
local ownerMotion = GetV(V_MOTION, GetV(V_OWNER, MyID)) if ( MOTION_MOVE == ownerMotion ) then -- 追加した条件 if ( distance > 3 or distance == -1) then -- MYOWNER_OUTSIGNT_IN MyState = FOLLOW_ST TraceAI ("IDLE_ST -> FOLLOW_ST") return; end end
global variableの次にHomunculusSafetyHP = 50を記入し、 function GetOwnerEnemy (myid)の所の最後 return result の直前に、
-- ホムンクルスの残りHPが一定%以下の場合は攻撃させない(=ターゲット放棄≒敵を取得しない) local HomunculusHP = GetV (V_HP,myid) local HomunculusMaxHP = GetV (V_MAXHP,myid) if ((HomunculusHP/HomunculusMaxHP)*100 < HomunculusSafetyHP) then result = 0 end
-- ここから追加 local EnemyFlg = false local EnemyID = GetV(7,id) local i for i in TargetEnemy do TraceAI (string.format("タゲNo:%d,ID:%d",i,TargetEnemy[i])) if (TargetEnemy[i] == EnemyID ) then TraceAI ("登録済み") EnemyFlg = true break end end if EnemyFlg == false then TargetEnemyCount = TargetEnemyCount + 1 TargetEnemy[TargetEnemyCount] = EnemyID TraceAI (string.format("タゲ登録No:%d,ID:%d",TargetEnemyCount,TargetEnemy[TargetEnemyCount])) end -- ここまで追加
MySkill = 0 MyEnemy = id MyState = ATTACK_OBJECT_CMD_ST
*修正コード("ここから修正〜ここまで修正"は元のコードをコメント化) function GetMyEnemyB (myid) local result = 0 local owner = GetV (V_OWNER,myid) local actors = GetActors () local enemys = {} local index = 1 local type
-- ここから修正 -- 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 -- end -- end -- end
for i,v in ipairs(actors) do local j local EnemyID = GetV(7,v) if (v ~= owner and v ~= myid) then if (1 == IsMonster(v)) then local target = GetV( V_TARGET, v) -- タゲってないmobで、登録されてるものは敵リスト追加 if target == 0 then for j in TargetEnemy do if (TargetEnemy[j] == EnemyID ) then TraceAI (string.format("タゲNo:%d,ID:%d",j,TargetEnemy[j])) enemys[index] = v index = index+1 break end end else enemys[index] = v index = index+1 end end end end -- ここまで修正
local type = GetV(V_HOMUNTYPE, MyID) local flag_sp = GetV(V_SP, MyID)
-- リーフの緊急回避 if ((type == LIF or type == LIF2 or type == LIF_H or type == LIF_H2) and (MyState == CHASE_ST or MyState == FOLLOW_ST)) then if (EmergencyAvoidDelay <= GetTick()) then if (flag_sp * 100 >= GetV(V_MAXSP, MyID) * SkillUseLimit) then -- SP残量が指定%以上の時 EACasting = true -- 発動フラグをONに end end
if (EACasting == true) then SkillObject(MyID, 3, IN_SKILL_EMERGENCYAVOID, MyID) -- 緊急回避レベル3使用 if (GetV(V_SP, MyID) < flag_sp) then -- SP消費時 EACasting = false -- フラグリセット EmergencyAvoidDelay = GetTick() + 35000 -- 次にかけ直すまでの時間 end end end end
function GetMyEnemyC (myid) local result = 0 local owner = GetV (V_OWNER,myid) local actors = GetActors () local enemys = {} local index = 1 local target local type for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then type = GetV(V_HOMUNTYPE,v) target = GetV (V_TARGET,v) if (target == myid) then enemys[index] = v index = index+1 elseif ((mob1) or (mob2) or (mob3) or (mob4)) then if (GetV(V_TARGET,v) == 0) then enemys[index] = v index = index + 1 end end end end
>>482 idがプレイヤーかどうかの判別なら>>340にあるが少し間違っているので勝手に修正 function IsPlayer(id) local TypeID = GetV(V_HOMUNTYPE,id) if ((0 <= TypeID and TypeID <= 23) or (4001 <= TypeID and TypeID <= 4044) or TypeID == 4046) then return 1 end return nil end
>>486 指定された座標の最も近い隣接マスに移動する function GetContactPoint (x1, y1) local MyX , MyY = GetV (V_POSITION, MyID) local x2 = x1 local y2 = y1 if (x1 < MyX) then x2 = x2 + 1 elseif (x1 > MyX) then x2 = x2 - 1 end if (y1 < MyY) then y2 = y2 + 1 elseif (x1 > MyX) then y2 = y2 - 1 end return x2, y2 end
function GetMyEnemyC (myid) local result = 0 local owner = GetV (V_OWNER,myid) local actors = GetActors () local enemys = {} local index = 1 local target local type for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then type = GetV(V_HOMUNTYPE,v) target = GetV (V_TARGET,v) if (target == myid) then enemys[index] = v index = index+1 elseif ((v == mob1) or (v == mob2) or (v == mob3) or (v == mob4)) then if (GetV(V_TARGET,v) == 0) then enemys[index] = v index = index + 1 end end end end
local min_dis = 100 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
>>496 すまん俺も間違えてた elseif ((v == mob1) or (v == mob2) or (v == mob3) or (v == mob4)) then←これも間違いで、 elseif ((type == mob1) or (type == mob2) or (type == mob3) or (type == mob4)) then←正しくはこう
461さんの設定で function GetMyEnemyB (myid) local result = 0 local owner = GetV (V_OWNER,myid) local actors = GetActors () local enemys = {} local index = 1 local type
local MyHP = GetV (V_HP,MyID) local MyMaxHP = GetV (V_MAXHP,MyID) local HPper = (MyHP / MyMaxHP) * 100
if (AwayHP >= HPper) then -- AwayHP以下だとアクティブに敵認識(逃亡用の敵認識) for i,v in ipairs(actors) do if (v ~= owner and v ~= myid ) then if (1 == IsMonster(v) and IsNotNoManner( myid, v )) then -- vがモンスターでタゲが無い、または自分か主人をタゲってる場合 if (3 >= GetDistance2 (myid, v)) then -- 自分との距離が3の敵を認識(逃亡用) enemys[index] = v -- 敵リストにvのidを追加 index = index+1
end end end end
else -- AwayHPより高い場合、ホムはアクティブ
if (AwayHP < HPper) then ← ここを追加 for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then -- vの値が主人のidでもホム自身のidでもない場合 if (1 == IsMonster(v) and IsNotNoManner( myid, v ) ) then -- vがモンスターでタゲが無い、または自分か主人をタゲってる場合 if (AttackArea >= GetDistance2 (GetV(V_OWNER,MyID), v)) then -- 主人との距離がAttackArea以下の場合 enemys[index] = v -- 敵リストにvのidを追加 index = index+1 end end end end
502 :488 :06/03/19 17:07 ID:VE0hUF9n
end
local min_dis = 100 local dis for i,v in ipairs(enemys) do dis = GetDistance2 (myid,v) -- 自分をタゲってる敵(v)との距離をdisに代入 if (dis < min_dis) then -- 距離が100未満だったら result = v -- resultへvを代入 min_dis = dis end end
>>501 else -- AwayHPより高い場合、ホムはアクティブ if (AwayHP < HPper) then ← ここを追加 for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then -- vの値が主人のidでもホム自身のidでもない場合 if (1 == IsMonster(v) and IsNotNoManner( myid, v ) ) then -- vがモンスターでタゲが無い、または自分か主人をタゲってる場合 if (AttackArea >= GetDistance2 (GetV(V_OWNER,MyID), v)) then -- 主人との距離がAttackArea以下の場合 enemys[index] = v -- 敵リストにvのidを追加 index = index+1 end end end end end □
単純にendが足りないだけだと思います endを□の位置に追加すれば直るはずです
でも「if (AwayHP < HPper) then ← ここを追加」を追加しなくても ifの「else」で同じ内容の分岐になるので 追加したif文は意味が無いと思います…
流れを無視して過去ログにあるか不明なものができたじぇ。 内容は『ケミのタゲ先を攻撃先に認識させる』というものだ。 ・・・まぁ単に function GetOwnerEnemy (myid) 中の文を応用しただけだが。 補足文はThe Winter's Taleのとこの注釈入れてあるようなもんだ、深く気にしないでくれ。
------------------------------------------- -- ケミが攻撃しようとしている敵のidをターゲットとして取得する(距離順に優先) -- <戻り値>敵のキャラクターid ------------------------------------------- function GetOwnerAtackEnemy (myid) local result = 0 -- 敵のキャラクターid local owner = GetV (V_OWNER,myid) -- ケミ自身のキャラクターid local actors = GetActors () -- 周りのキャラクターidを全部取得 local enemys = {} -- 敵のリスト local index = 1 -- インデックス番号(初期値1) local target -- ターゲットのキャラクターid
-- (1,actors[1])、(2,actors[2])、…のペアを繰り返す -- 周りのキャラクターidをひとつひとつチェックして、そのキャラクターに -- ケミが攻撃しようとしていたら、ケミのタゲをホムのターゲットとして取得 for i,v in ipairs(actors) do if (v == owner) then -- ケミならば local motion = GetV(V_MOTION,v) -- そのキャラクターのモーションを取得 -- モーションが攻撃モーションだったら if (motion == MOTION_ATTACK or motion == MOTION_ATTACK2) then target = GetV (V_TARGET,v) -- そのキャラクター(ケミ)のタゲを取得 enemys[index] = target -- 敵のリストに追加 index = index+1 -- インデックスを1増やす end end end
local min_dis = 100 -- 最小距離(初期値は100) local dis -- 距離 -- (1,enemys[1])、(2,enemys[2])、…のペアを繰り返す -- 敵リストの中で、ホムから一番近い敵をホムの攻撃対象とする 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
タブの部分は全角スペースになってるので導入時はタブに変換がいいかと。 文を入れる先は優先順位的に function GetOwnerEnemy (myid) のあとがいいと思われる。 一応動作確認済みだけど、他のコードは等速のしか入れてないから競合とかはどうなるか不明。
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
function Cast_Venediction(MyID)を攻撃のルーチンの中に入れることを前提にして
function Cast_Venediction(myid)
local my_sp = GetV (V_SP,myid) local my_maxsp = GetV (V_MAXSP,my id) local mysp_sp_persent = (my_sp / my_maxsp) * 100.0
local my_owner = GetV(V_OWNER,myid)
local my_owner_hp = GetV(V_HP,my_owner) local my_owner_maxhp = GetV(V_MAXHP,my_owner) local my_owner_hp_persent = (my_owner_hp / my_owner_maxhp) * 100.0
if(type == VANILMIRTH or type == VANILMIRTH_H or type == VANILMIRTH2 or type == VANILMIRTH_H2) then if(mysp_sp_persent >= 70 and my_owner_hp_persent <= 30) then SkillObject(myid, 5, 8014, GetV(V_TARGET,myid)) return 1 end end
if ( x == MyDestX and y == MyDestY and MOTION_MOVE == GetV(V_MOTION,MyID)) then return -- 目的地と現在地が同一の場合は、処理しない end
local curX, curY = GetV (V_POSITION,MyID) if (math.abs(x-curX)+math.abs(y-curY) > 15) then -- 目的地が一定距離以上なら (サーバーで遠距離は処理しないため) List.pushleft (ResCmdList,{MOVE_CMD,x,y}) -- 元の目的地への移動を予約する x = math.floor((x+curX)/2) -- 中間地点へ移動する y = math.floor((y+curY)/2) -- end
function UseComboSkill(skillId, list, maxCombo, index, spRemainPer) -- 終了条件(コンボ完了、SP不足) if index == 0 then return 0 end -- コンボ開始じゃない if index > maxCombo then return 0 end -- コンボ終了 -- SP残%割るのでここで終了 if math.floor(GetV(V_SP, MyID) / GetV(V_MAXSP, MyID) * 100) < spRemainPer then return 0 end -- SP足りないのでここで終了 if GetV(V_SP, MyID) < SKILLUSESP[skillId][list[index]] then return 0 end -- ディレイ待機中 if (ComboDelay ~= 0) and (ComboDelay > GetTick()) then return index end -- 攻撃中? if MyState ~= ATTACK_ST then return index end -- スキル実行 SkillObject(MyID, list[index], skillId, MyEnemy) ComboDelay = GetTick() + SKILLTOSKILLINTERVAL -- ディレイセット index = index + 1 -- コンボカウンタ加算 return index end
自己解決しました。 function OnRUNAWAY_ST () TraceAI ("OnRUNAWAY_ST")
local distance = GetDistanceFromOwner(MyID) if ( distance > AwayRange or distance == -1) then -- Mobから逃げるより主人を追う方を優先 MyState = FOLLOW_ST TraceAI ("RUNAWAY -> FOLLOW_ST") return; end
を部分を以下のとおりに書き換え
function OnRUNAWAY_ST () TraceAI ("OnRUNAWAY_ST")
local distance = GetDistanceFromOwner(MyID) local MyHP = GetV (V_HP,MyID) local MyMaxHP = GetV (V_MAXHP,MyID) local HPper = (MyHP / MyMaxHP) * 100
if (AwayHP < HPper) then MyState = ATTACK_ST TraceAI (" ATTACK_ST -> RUNAWAY") return;
else if ( distance > AwayRange or distance == -1) then -- Mobから逃げるより主人を追う方を優先 MyState = FOLLOW_ST TraceAI (" RUNAWAY -> FOLLOW_ST") return; end end
よくよく見直してみると>>570のコードそのままじゃ、 最初のコンボスキル発動→手動スキル発動→2番目のコンボスキル発動になりますね…。 >>570の修正点だけ書いておきます。 ↓この行を、 if skill == 8009 and level == 3 then ComboCounter = 1 -- ムーンライトレベル3ならば ↓のように修正。 if skill == 8009 and level == 3 then -- コンボ発動中に再度トリガが起動された場合にカウンタが1に戻るのを防ぐ if ComboCounter == 0 then ComboCounter = 1 end end
elseif (MySkill == 8001 and HomunculusHeal == 1) then if (HomunculusDeadlineHP > (HomunculusHP / HomunculusMaxHP)*100 or OwnerDeadlineHP > (OwnerHP / OwnerMaxHP)*100) then SkillObject (MyID,MySkillLevel,MySkill,MyID) ActionFlag = 1 TraceAI ("ATTACK_ST -> ATTACK_ST : AUTO_HEAL") end end
list = List.new() List.pushright(list, 1) for i,v in ipairs(list) do print(i,v) end --> 「1 1」を期待するも反応なし print(list[0]) --> 1 for k,v in pairs(list) do print(k,v) end --[[ 0 1 first 0 last 0 --]]
>>601-603 こういう関数を作れば function List.new2(...) local list = List.new() for i, v in arg do List.pushright(list, v) end return list end こう書けて幸せになれるかも mob1 = List.new2(1002, 1063)
それともこういうのを作って Array = {} function Array.search(array, val) for i, v in array if (v == val) then return i end end return nil end こうしてもいいかも mob1 = { 1002, 1063 } if (Array.search(mob1, GetV(V_HOMUNTYPE, id)))
>>615 forのところ思いっきり間違えてた_| ̄|○ function List.new2(...) local list = List.new() for i, v in ipairs(arg) do List.pushright(list, v) end return list end と function Array.search(array, val) for i, v in ipairs(array) do if (v == val) then return i end end return nil end
for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then type = GetV(V_HOMUNTYPE,v) target = GetV (V_TARGET,v) if (target == myid) then enemys[index] = v index = index+1 elseif (ここだと思う) then if (GetV(V_TARGET,v) == 0) then enemys[index] = v index = index + 1 end end end
function OnMOVE_CMD(x,y) --{ --# 関数呼ばれた時間を取得して比較 if( (GetTick() - MoveTimeSet) > 2000) then --{ MoveTimeSet = GetTick() MoveTimeX = x MoveTimeY = y MoveTimeFlag = 0 --} else --{ if(x == MoveTimeX and y == MoveTimeY) then --{ MoveTimeFlag = 1 end --} end --} (略
mobdata.luaを利用して、 MoveMob = MOBDATA[GetV (V_HOMUNTYPE,id)][M_V_MOVE] のように敵が静止型どうかの情報を取得しているのですが、 一覧にまだ含まれていない敵の場合どのように対処すればよろしいでしょうか? ご教授願います。 エラーメッセージは、attempt to index field '?'(a nil value)です。
if( MOBDATA[GetV (V_HOMUNTYPE,id)][M_V_MOVE] ~= nil ) then MoveMob = MOBDATA[GetV (V_HOMUNTYPE,id)][M_V_MOVE] end という方法も試みましたが、同一のエラー(if分の行で)が 起きます。
for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then type = GetV(V_HOMUNTYPE,v) target = GetV (V_TARGET,v) if (target == myid) then enemys[index] = v index = index+1
elseif (MOBACT[type] ~= nil and MOBACT[type][M_V_ACT] == 2) then if (GetV(V_TARGET,v) == 0) then enemys[index] = v index = index + 1 end end end end
for i,v in ipairs(actors) do if (v ~= owner and v ~= myid) then target = GetV (V_TARGET,v) if (target == myid or target == owner) then --←この行 enemys[index] = v index = index+1 end end end
戦闘中にターゲットが第3者と重複していないかチェックする関数 OnCHASE_ST()関数とOnATTACK_ST()関数内の適切な場所に、 if IsOverlapTarget(MyEnemy) == true then MyState = IDLE_ST MyEnemy = 0 return end とでも書けばターゲットがかぶった瞬間に攻撃動作をやめます。 が、弊害として今度はPTプレイ中に一切攻撃に参加しなくなります(苦笑)。
#そこらへんのチェックは他の人にまかせた(ぉ
---------------------------------- -- ターゲットが重複しているか? ---------------------------------- function IsOverlapTarget(nowtarget)
-- 現在のターゲットがケミでもホムでもない第3者をターゲットにした local target = GetV(V_TARGET, nowtarget) if (target ~= 0) and (target ~= MyOwner) and (target ~= MyID) then return true end
local actors = GetActors() for i,v in ipairs(actors) do if IsMonster(v) == 0 then if (v ~= MyOwner) and (v ~= MyID) then target = GetV(V_TARGET, v) -- ターゲットが第3者とかぶっている? if target == nowtarget then if (GetV(V_MOTION, v) == MOTION_ATTACK) or (GetV(V_MOTION, v) == MOTION_ATTACK2) then return true end end end end end
失礼、>>724の関数自己解決。 以下のようにすればケミ自身が殴ってる場合にかぎり、重複していないと判断されます。 function IsOverlapTarget(nowtarget)
local result = false
-- 現在のターゲットがケミでもホムでもない第3者をターゲットにした local target = GetV(V_TARGET, nowtarget) if (target ~= 0) and (target ~= MyOwner) and (target ~= MyID) then result = true end
-- ターゲットを第3者が殴っているかどうか? local actors = GetActors() for i,v in ipairs(actors) do if IsMonster(v) == 0 then if (v ~= MyOwner) and (v ~= MyID) then target = GetV(V_TARGET, v) -- ターゲットが第3者とかぶっている? if target == nowtarget then if (GetV(V_MOTION, v) == MOTION_ATTACK) or (GetV(V_MOTION, v) == MOTION_ATTACK2) then result = true end end end end end
-- ケミ自身がターゲットを殴っている場合はかぶってないものとする if result == true then if GetV(V_MOTION, MyOwner) == MOTION_ATTACK or GetV(V_MOTION, MyOwner) == MOTION_ATTACK2 then if GetV(V_TARGET, MyOwner) == nowtarget then result = false end end end
AI関数内部でGetDistance2の返り値-1を期待する部分があるので改変できない またUtil.luaはユーザー同士、内部が同じであるという前提があるので改変できない よってGetOwnerEnemy、GetMyEnemy関数の距離判定で-1を除外する必要がある 具体的には if (dis < min_dis and dis ~= -1) then
>>794 elseif ownerY > y and ownerX == x elseif ownerY < y and ownerX == x elseif ownerY == y and ownerX > x elseif ownerY == y and ownerX < x のようにそれぞれ設定するか、 あるいは等号付き不等号(>=,<=)を使ってほかの方向と 同じ処理をさせるようにすると上手くいくはず。多分。
function clone( A ) -- http://lua-users.org/lists/lua-l/2003-05/msg00077.html local T = type(A) if T == "string" then return string.sub(A,1) elseif T == "number" or T == "boolean" or T == "function" then --does function need to be handled differently? local B = A --do I have to do this or will (return A) return a copy return B elseif T=="table" then local Build={} local function cloneItem(i,v) Build[i] = clone(v) end table.foreach( A, cloneItem) return Build else return nil end end
function extends( obj, base ) -- 継承 return setmetatable( obj, { __index = base } ) end
function super( obj ) -- スーパークラスの参照 return getmetatable( obj ) and getmetatable( obj ).__index end
function new( class ) -- 新しいオブジェクトの作成 return setmetatable( clone( class ), { __index = super( class ) } ) end
>803 常時読み書きする必要があるか ini ファイル型式にこだわる必要がないんだったら mobdata.lua 使えば?
require "./AI/mobdata.lua"
function istActive (MobID) -- 返り値:データナシ=nil,アクティブ=1,ノンアク=0 local result=nil if (MOBDATA[MobID] and MOBDATA[MobID][M_V_ACTIVE]) then result = MOBDATA[MobID][M_V_ACTIVE] end return result end
>>801 たぶんこれでいいはず。 local dx = ownerX - x local dy = ownerY - y dx = dx == 0 and 0 or dx / math.abs(dx) * 5 -- 0でなければ符号抜いて5倍 dy = dy == 0 and 0 or dy / math.abs(dy) * 5 Move(MyID, ownerX + dx, ownerY + dy)
function AI (x) if (MS == 0) then if ( GetD(x) > 3) then MS = 1 end elseif (MS == 1) then if (GetD(x) <= 2) then MS = 0 elseif (GetV (3, x) == 0) then MoveToOwner (x) end end end
function GetD (y) local a, b = GetV (1,GetV(0,0)) local c, d = GetV (1,y) if (a == -1 or c == -1) then return 99 end return math.floor(math.sqrt((a-c)^2+(b-d)^2)) end
とりあえず省きまくればここまではいけるかな。 なんだこりゃAIか本当に。 require "./AI/Const.lua" require "./AI/Util.lua" function AI(myid) if(GetDistanceFromOwner(myid) > 3) then MoveToOwner(MyID) end end
function AI( myid ) local actors = GetActors() local tick = GetTick() for i,v in ipairs(actors) do TraceAI( string.format( "[%d] ID=%d / Type=%d", tick, v, GetV( V_HOMUNTYPE, v ) ) ) end end
-- プレイヤーキャラ・もしくはホムンクルスかどうかの判定 function IsPlayer(id) if (id == nil or id <= 0 or id < 65536) then -- IDが未定義かNPC return false end local type = GetV(V_HOMUNTYPE,id) if (0 <= type and type <= 23) then -- 転生前・スパノビ・ホムンクルス(0〜23) return true end if (4001 <= type and type <= 4046) then -- 転生職・ベビー(4001〜4046) return true end return false end
未定義モンスターIDでエラーが出る場合はMOBDATA[id][M_V_***]を参照する前に if (MOBDATA[id] ~= nil) then 等、事前に未定義かどうかのチェックを行ってください。
自分はID調査用にAlt+TをトリガとしてGetActors()で画面内一括取得する関数を作って対応しています。 ex) string.format("[ x , y ]\t%s\t%s\t%s",x座標,y座標,生ID,GetV(V_HOMUNTYPE,id),固有名称) 固有名称にはIsMonsterとIsPlayerでmobdata.luaとplayerjobdata.luaから名称を入れ、 その他、未定義にはHOMUNTYPEをそのままですね。
function GetMobData(mobid,attr) if (MOBDATA == nil or MOBDATA[mobid] == nil or MOBDATA[mobid][attr] == nil) then return nil end return MOBDATA[mobid][attr] end
name = GetMobData(1001,M_V_NAME) if (name ~= nil) then TraceAI(name) end
>>942 local path = "./path/filename.lua" local fh = io.open(path, "w") for i,v in ipairs(DATA) do fh:write(string.format("DATA[%d] = {%d, %d, %d}\n", i, unpack(v)) end fh:close()
-- バニル迫害処理 function TrampolineVanilmirth() if (GetV(V_HOMUNTYPE,MyID) == LIF) then local actors = GetActors() for i,id in ipairs(actors) do if (GetV(V_HOMUNTYPE,id) == VANILMIRTH) then if (id > 0 and id < 65536) then Move(MyID,GetV(V_POSITION,id)) end end end end end
function GetMyEnemy (myid) local result = 0 if ( ActiveFlag == 1 ) then result = GetMyEnemyB (myid) else result = GetMyEnemyA (myid) end return result end