--[[ RacerAI version 1.2 (2008/02/01) Lif Only. リーフ専用。 Author: silica as 冬物語の人 http://winter.sgv417.jp/ Document: http://pc3merchant.net/ai_antenna/?AI%BE%DC%BA%D9%2FRacerAI Special Thanks: 青いリボンで結びます / ちずきち様 http://blue.ap.teacup.com/ribbon/ 初回限定のAI配布。 / 初回限定様 http://pc3merchant.net/ai/ --]] -- 全体設定 local AI_PATH = "./AI/" -- メインAI --local AI_PATH = "./USER_AI/" -- ユーザーAI -- 優先度 左→右:高→低 エンペリウム、黒いきのこ、赤いきのこ local TYPEIDS = {1288, 1084, 1085} local MIN_DIS = 5 -- 最低攻撃範囲(これ以上離れていれば自動安息) local UE_Lv = 5 -- 緊急回避レベル(default: 5) local SKIP = 5 -- mainAI()内の処理周期をSKIP回省略 local USE_MC = 0 -- 優先度1: モーションキャンセル(0:OFF / 1:ON) local USE_NMC = 1 -- 優先度2: ゼロ移動キャンセル(0:OFF / 1:ON) local MIN_SP = 50 -- モーションキャンセル使用下限SP local MULTI_ATTACK = 3 -- 多重攻撃(目安は1〜3回まで) local SKIPCOUNT = 0 -- 処理飛ばし用カウンタ local MOTION = 0 -- モーションキャンセル初期設定 -- 定数 V_OWNER = 0 -- 主人のID V_POSITION = 1 -- 座標 (x, y) V_TYPE = 2 -- 種類(未実装) V_MOTION = 3 -- 現在動作 V_ATTACKRANGE = 4 -- 攻撃範囲(未実装。現在は1セルに固定) V_TARGET = 5 -- 攻撃、スキル使用対象の ID V_SKILLATTACKRANGE = 6 -- スキル攻撃範囲(未実装) V_HOMUNTYPE = 7 -- ホムンクルスの種類 V_HP = 8 -- HP (ホムンクルスと主人) V_SP = 9 -- SP (ホムンクルスと主人) V_MAXHP = 10 -- 最大 HP (ホムンクルスと主人) V_MAXSP = 11 -- 最大 SP (ホムンクルスと主人) -- (x1, y1)と(x2, y2)の最短距離(方形上) -- 円: return math.floor(math.sqrt((x1-x2)^2+(y1-y2)^2)) function GetDistanceSquare(x1, y1, x2, y2) local xpos = math.abs(x1 - x2) -- X座標上の距離 local ypos = math.abs(y1 - y2) -- Y座標上の距離 if(xpos >= ypos) then return xpos else return ypos end end -- id1とid2の最短距離 function GetDistance2(id1, id2) local x1, y1 = GetV(V_POSITION, id1) local x2, y2 = GetV(V_POSITION, id2) if(x1 == -1 or x2 == -1) then -- X, Yのどちらかが負なら不正値 return -1 end return GetDistanceSquare(x1, y1, x2, y2) end -- 現在の残HP% function GetPercentHP(id) return((GetV(V_HP, id) / GetV(V_MAXHP, id)) * 100.0) end -- 現在の残SP% function GetPercentSP(id) return((GetV(V_SP, id) / GetV(V_MAXSP, id)) * 100.0) end -- メンタルチェンジ:ホムSP100以上, SkillLv省略可 -- 消費SP: 固定, Lv1-3 function MentalChange(myid, lv) lv = lv or 3 -- デフォルトLv3 if(GetV(V_SP, myid) >= 100) then SkillObject(myid, lv or 3, 8004, myid) -- メンタルチェンジ end end -- 緊急回避:ホムSP40以上, SkillLv省略可 -- 消費SP: 15+SkillLv×5, Lv1-5 function UrgentEscape(myid, lv) local sp = 15 + ((lv or 5) * 5) -- デフォルトLv5 local mysp = GetV(V_SP, myid) -- ホムの現在SP if(100 <= mysp and mysp <= 150) then -- SPが100以上〜150以下ならメンタルチェンジでSPを全快 MentalChange(myid) end if(mysp >= sp) then SkillObject(myid, lv, 8002, myid) -- 緊急回避 end end -- TypeIDを探索して目標IDを見つけたら情報を返す function SeekTypeID(actors, typeids) local target = {} -- ターゲット情報テーブル target.exist = false -- ターゲット発見/未発見 -- ターゲットを探す for index, typeid in ipairs(typeids) do for i, v in ipairs(actors) do if(typeid == GetV(V_HOMUNTYPE, v)) then target.exist = true -- 発見 target.id = v -- ターゲットID target.x, target.y = GetV(V_POSITION, v) -- 位置 break end end -- ターゲットは先に見つけたものだけにする。 if target.exist then break end end return target end -- モーションキャンセル from 初回限定AI AImain.lua MotionCancel2() function MotionCancel(myid, myenemy) zx, zy = GetV(V_POSITION, myenemy) if(MOTION == 0) then Move(myid, zx+1, zy) Move(myid, zx, zy+1) MOTION = 1 else Move(myid, zx-1, zy) Move(myid, zx, zy-1) MOTION = 0 end end -- ゼロ移動キャンセル from 初回限定AI AImain.lua MotionCancel3() function NotMoveCancel(myid, myenemy) zx, zy = GetV(V_POSITION, myid) Move(myid, zx, zy) end function AImain(myid) -- myid: ホムID local ownerid = GetV(V_OWNER, myid) -- ホムの主人ID local actors = GetActors() -- IDテーブル local msg = GetMsg(myid) -- 命令を受ける local rmsg = GetResMsg(myid) -- 予約命令を受ける local boost = 0 -- 攻撃速度加速 -- コマンド受付処理 if msg[1] == 1 then -- MOVE_CMD (Alt+右クリック) Move(myid, msg[2], msg[3]) elseif msg[1] == 3 then -- ATTACK_OBJECT_CMD (対象をAlt+右クリック) Attack(myid, msg[2]) elseif msg[1] == 7 then -- SKILL_OBJECT_CMD (ホムスキル) SkillObject(myid, msg[2], msg[3], msg[4]) -- Alt+Tを押している間のみ、攻撃速度を通常に戻す elseif msg[1] == 9 then -- FOLLOW_CMD (Alt+T) boost = 1 end -- 画面内から目標のTypeIDを探して情報を返す target = SeekTypeID(actors, TYPEIDS) -- ターゲットが視野範囲内にいるかどうか? if(target.exist) then -- 実行を一定回数省略 SKIPCOUNT = SKIPCOUNT+1 if(SKIPCOUNT > SKIP or boost == 1) then -- SKIP回を超えたら SKIPCOUNT = 0 else -- まだSKIP回になっていない return end -- 目標までの距離を取得 distance = GetDistance2(myid, target.id) -- 目標に隣接していない if(2 < distance and distance <= MIN_DIS) then MentalChange(myid) -- メンタルチェンジ Move(myid, target.x, target.y) -- ターゲットと同じ位置に移動 -- 時々ターゲットの隣にはじき出されます。 -- 目標距離が2以内になれば攻撃開始 elseif(distance <= 2) then for i=1, MULTI_ATTACK do -- 攻撃多重化 Attack(myid, target.id) -- ターゲットを攻撃 end if(USE_MC == 1) then -- モーションキャンセル if(GetV(V_SP, myid) >= MIN_SP) then MotionCancel(myid, target.id) else -- ゼロ移動キャンセル NotMoveCancel(myid, target.id) end elseif(USE_NMC == 1) then -- ゼロ移動キャンセル NotMoveCancel(myid, target.id) end -- 目標から遠く離れている else UrgentEscape(myid, UE_Lv) -- 自動緊急回避 end else UrgentEscape(myid, UE_Lv) -- 自動緊急回避 end end -- エラー内容をファイルに出力 function write(file, str) local fp = io.open(string.format(AI_PATH.."%s", file), "a") if(fp == nil) then return end fp:write(string.format("%s : %s\n", os.date("%Y/%m/%d %H:%M:%S"), str) ) fp:close() end -- エラーが出たらAI関数を空のAI関数に差し替え function try(func, ...) local ok, err = pcall(func, unpack(arg)) if(not ok) then write("Error.txt", err) -- エラー内容をファイルへ AI = function() end -- エラーが出たらAI()関数を空にする end end -- エラー対策 function AI(myid) try(AImain, myid) end