戻る

2006/3/28カスタムAIVer3:アミストル専用


AI_2はこちら
-- ※"require"のある行からコピペで、AI.luaへ上書き貼り付けして使用してください※
-- ※使用は自己責任で※

-- ・コードが長くなったので 2ファイル に分けてます
-- ・これはVer3をアミストル専用にまとめたものです
-- ・他のホムンクルスでこのAIを使用するとエラー落ちします
-- ・デフォルトで先行型になっているので、非先行型が好みの方は
-- function GetMyEnemy (myid)内の GetMyEnemyB (myid) を GetMyEnemyA (myid)に変えて使用してください
----------------------------------------
-------------------------------------------------
-- 参考AI
-- The Winter's Tale
-- http://www.sgv417.jp/~winter/index.html

-- 0-MATERIAL (ぜろ・まてりある)
-- http://www.kogarashi.jp/0-material/

-- 工体研究所rev10
-- http://blog.livedoor.jp/aidev/archives/50119284.html

-- くま○〜@ガルムのAIファイル配布
-- http://www.kmzw.jp/nb/ai.html

-- アルケミストのAIを語るスレ2
-- http://enif.mmobbs.com/test/read.cgi/livero/1140506800/l50

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

-- ホムンクルスAIについての雑談・要望スレ
-- http://enif.mmobbs.com/test/read.cgi/livero/1142513331/l50

-------------------------------------------------
require "./AI/Const.lua"
require "./AI/Util.lua"
require	"./AI/USER_AI/AI_2.lua"	

-----------------------------
-- state(ホムの状態関数)
-----------------------------
IDLE_ST					= 0	-- 待機状態
FOLLOW_ST				= 1	-- 所持者追従状態	
CHASE_ST				= 2	-- ターゲット追跡状態
ATTACK_ST				= 3	-- 攻撃状態
--
MOVE_CMD_ST				= 4
STOP_CMD_ST				= 5
ATTACK_OBJECT_CMD_ST			= 6
ATTACK_AREA_CMD_ST			= 7
PATROL_CMD_ST				= 8
HOLD_CMD_ST				= 9
SKILL_OBJECT_CMD_ST			= 10
SKILL_AREA_CMD_ST			= 11
FOLLOW_CMD_ST				= 12
--
RUNAWAY_ST				= 13	-- 追加関数(逃亡処理)
AUTOSKILL_ST				= 14	-- 追加関数(オートスキル処理)
AMISTR_ST				= 15	-- 追加関数(アミストル専用)

----------------------------

------------------------------------------
-- global variable(処理内部で使うグローバル変数)
------------------------------------------
MyState				= IDLE_ST	-- ホムの現在状態(初期値は待機状態)
MyEnemy				= 0		-- ホムがターゲットしている敵のキャラクターID
MyDestX				= 0		-- ホムの目標座標X(移動先 / スキル使用座標)
MyDestY				= 0		-- ホムの目標座標Y(移動先 / スキル使用座標)
MyPatrolX				= 0		-- ホムの偵察目的地 x座標
MyPatrolY				= 0		-- ホムの偵察目的地 y座標
ResCmdList				= List.new()	-- 予約コマンドリスト
MyID					= 0		-- ホムンクルス自身のid
MySkill					= 0		-- ホムンクルスの使用スキル
MySkillLevel				= 0		-- ホムンクルスの使用スキルレベル
------------------------------------------
------------------------------------------
-- 追加分global variable(ここの初期値をいじることでホムの設定をカスタマイズできる)
------------------------------------------
AttackArea				= 6		-- アクティブ状態の時、主人からこの距離のMobを殴りに行く
AwayRange				= 4		-- 主人からどのくらい離れたところまで逃げるか
AwayHP					= 40		-- 何%でホムが逃げるか
ActionSwitch				= 1		-- テレポ、マップ移動後即座にホムが敵を攻撃しにいかない(yes=1 no=0)(先行時のみ)

-- オートスキル設定
AutoSkill				= 20		-- ホムの自動スキルの最高確率(%)(SPが減ると確率減少、フィーリルとバニルミストのみ)
AutoSkill_SP				= 40		-- ホムのSPがこの%を下回った場合には自動スキル発動なし

-- アミストルのオートスキル設定
CastlingLv				= 5		-- キャスリングの使用Lv(アミストルのみ)
CastOwner				= 10		-- 主人のHPが何%で自動キャスリング(アミストルのみ)
CastWay					= 6		-- 主人から何セル離れた場所でキャスリングするか(アミストルのみ)
CastSwitch				= 1		-- 自動でキャスリングするかどうかスイッチ(yes=1 no=0)

-- その他
Timer1					= GetTick()	-- タイマー1、現在時刻格納
MoveTime				= 500		-- 移動時の座標更新間隔
MoveTime2				= 0		-- 移動時の座標更新用タイマー1

Castling				= 1		-- キャスリングしたかどうかの印、変更しないほうが無難
NoAttackSwitch				= 0		-- 設定Mobを殴らないスイッチ、いじってはダメ※先行時のみ効果有り※
AwayEnwmySwitch				= 0		-- 逃亡時設定Mobからは逃げないスイッチ、いじってはダメ
------------------------------------------

----------------------------------------------------
-- 手動(予約)処理
------------- command process  ---------------------
----------------------------------------------------
-- 移動命令(地面をALT+右クリック)
----------------------------------------------------
----------------------------------------------------
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	-- 目的地が一定距離(15セル)以上なら (サーバーで遠距離は処理しないため)
		List.pushleft (ResCmdList,{MOVE_CMD,x,y})	-- 元の目的地への移動を予約する
		x = math.floor((x+curX)/2)					-- 予約した地点と現在位置の中間地点へ移動する
		y = math.floor((y+curY)/2)					-- 同上
	end
	-- 移動処理
	Move (MyID,x,y)	
	MyState = MOVE_CMD_ST -- 移動状態へ、以下初期化
	MyDestX = x
	MyDestY = y
	MyEnemy = 0
	MySkill = 0
end

----------------------------------------------------
-- 停止命令(未実装)
----------------------------------------------------
----------------------------------------------------
function	OnSTOP_CMD ()
	TraceAI ("OnSTOP_CMD")

	if (GetV(V_MOTION,MyID) ~= MOTION_STAND) then	-- 現在の命令がSTANDでない場合
		Move (MyID,GetV(V_POSITION,MyID))	-- ホム自身の座標へ移動(その場で停止)
	end
	MyState = IDLE_ST	-- 待機状態へ、以下初期化
	MyDestX = 0
	MyDestY = 0
	MyEnemy = 0
	MySkill = 0
end

----------------------------------------------------
-- 指定目標への攻撃命令(対象を ALT+右ダブルクリック or ALT+右クリック2回目)
----------------------------------------------------
----------------------------------------------------
function	OnATTACK_OBJECT_CMD (id)
	TraceAI ("OnATTACK_OBJECT_CMD")

	MySkill = 0
	MyEnemy = id 		-- 指定目標のidをホムのターゲットに指定
	MyState = CHASE_ST 	-- 指定目標を追跡

end
----------------------------------------------------
-- 指定座標への攻撃命令(未実装)
----------------------------------------------------
----------------------------------------------------
function	OnATTACK_AREA_CMD (x,y)
	TraceAI ("OnATTACK_AREA_CMD")
	if (x ~= MyDestX or y ~= MyDestY or MOTION_MOVE ~= GetV(V_MOTION,MyID)) then
		Move (MyID,x,y)		-- 座標目標と指定座標が違う、または現在の状態が移動状態ではない場合、指定座標まで移動
	end
	MyDestX = x
	MyDestY = y
	MyEnemy = 0	-- ターゲットリセット
	MyState = ATTACK_AREA_CMD_ST	-- 範囲攻撃開始
end
----------------------------------------------------
-- 偵察(移動)命令(未実装)
----------------------------------------------------
----------------------------------------------------
function	OnPATROL_CMD (x,y)

	TraceAI ("OnPATROL_CMD")

	MyPatrolX , MyPatrolY = GetV (V_POSITION,MyID)	-- 偵察目的地に現在のホムの座標を代入
	MyDestX = x		-- 指定座標を目標座標に設定
	MyDestY = y
	Move (MyID,x,y)
	MyState = PATROL_CMD_ST		-- 偵察開始

end
----------------------------------------------------
-- (未実装)
----------------------------------------------------
----------------------------------------------------
function	OnHOLD_CMD ()
	TraceAI ("OnHOLD_CMD")
	MyDestX = 0
	MyDestY = 0
	MyEnemy = 0
	MyState = HOLD_CMD_ST
end
----------------------------------------------------
-- 指定目標へスキルを使う命令
----------------------------------------------------
----------------------------------------------------
function	OnSKILL_OBJECT_CMD (level,skill,id)
	TraceAI ("OnSKILL_OBJECT_CMD")
	MySkillLevel = level
	MySkill = skill
	MyEnemy = id
	MyState = CHASE_ST 
end
----------------------------------------------------
-- 指定座標へスキルを使う命令(未実装)
----------------------------------------------------
----------------------------------------------------
function	OnSKILL_AREA_CMD (level,skill,x,y)
	TraceAI ("OnSKILL_AREA_CMD")
	Move (MyID,x,y)
	MyDestX = x
	MyDestY = y
	MySkillLevel = level
	MySkill = skill
	MyState = SKILL_AREA_CMD_ST
end

----------------------------------------------------
-- 主人追尾命令(ALT+T)、追尾状態と待機状態を互いに転換させる
----------------------------------------------------
----------------------------------------------------
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 = IDLE_ST		-- 待機コマンド実行中だった場合、待機状態に
		MyEnemy = 0 
		MySkill = 0
		TraceAI ("FOLLOW_CMD_ST --> IDLE_ST")
	end
end
----------------------------------------------------
-- 手動(予約)処理、本体
-- クライアントからのコマンドを解釈し対応する関数へ渡す 
----------------------------------------------------
----------------------------------------------------
function	ProcessCommand (msg)
	if		(msg[1] == MOVE_CMD) then	-- msg[1]が移動コマンドだった場合
		OnMOVE_CMD (msg[2],msg[3])		-- msg[2]とmsg[3]の値をそれぞれOnMOVE_CMDのxとyへ
		TraceAI ("MOVE_CMD")
	elseif	(msg[1] == STOP_CMD) then		-- msg[1]が停止コマンドだった場合(未実装)
		OnSTOP_CMD ()
		TraceAI ("STOP_CMD")
	elseif	(msg[1] == ATTACK_OBJECT_CMD) then	-- msg[1]が指定目標への攻撃コマンドだった場合
		OnATTACK_OBJECT_CMD (msg[2])		-- msg[2]をOnATTACK_OBJECT_CMDのidへ
		TraceAI ("ATTACK_OBJECT_CMD")
	elseif	(msg[1] == ATTACK_AREA_CMD) then	-- msg[1]が指定座標への攻撃コマンドだった場合(未実装)
		OnATTACK_AREA_CMD (msg[2],msg[3])
		TraceAI ("ATTACK_AREA_CMD")
	elseif	(msg[1] == PATROL_CMD) then		-- msg[1]が偵察(移動)コマンドだった場合(未実装)
		OnPATROL_CMD (msg[2],msg[3])
		TraceAI ("PATROL_CMD")
	elseif	(msg[1] == HOLD_CMD) then		-- msg[1]がホールドコマンドだった場合(未実装)
		OnHOLD_CMD ()
		TraceAI ("HOLD_CMD")
	elseif	(msg[1] == SKILL_OBJECT_CMD) then	-- msg[1]が指定対象へのスキルコマンドだった場合
		OnSKILL_OBJECT_CMD (msg[2],msg[3],msg[4],msg[5])	-- それぞれ、OnSKILL_OBJECT_CMD (level,skill,id)へ代入
		TraceAI ("SKILL_OBJECT_CMD")
	elseif	(msg[1] == SKILL_AREA_CMD) then		-- msg[1]が指定座標へのスキルコマンドだった場合(未実装)
		OnSKILL_AREA_CMD (msg[2],msg[3],msg[4],msg[5])		-- それぞれ、OnSKILL_AREA_CMD (level,skill,x,y)へ代入
		TraceAI ("SKILL_AREA_CMD")
	elseif	(msg[1] == FOLLOW_CMD) then		-- msg[1]が追尾コマンドだった場合
		OnFOLLOW_CMD ()
		TraceAI ("FOLLOW_CMD")
	end
end

-----------------------------------------------------
-- 基本処理(ホムの状態関数)
-------------- state process  -----------------------
----------------------------------------------------
-- 待機処理
----------------------------------------------------
----------------------------------------------------
function	OnIDLE_ST ()
	
	TraceAI ("OnIDLE_ST")

	local cmd = List.popleft(ResCmdList)
	if (cmd ~= nil) then		
		ProcessCommand (cmd)	-- 予約コマンド処理 
		return 
	end
----------------------------------------------------
	if (GetV(V_MOTION, GetV(V_OWNER,MyID)) == MOTION_MOVE) then	-- 主人が移動状態だったら
		ActionSwitch = 0			-- テレポ、マップ移動後、主人が動き出したらスイッチOFF
	end
----------------------------------------------------
	if (ActionSwitch == 0) then			-- スイッチOFFだったら行動開始
		local	object = GetOwnerEnemy (MyID)	-- 所持者(ケミ)のidをobjectへ
		if (object ~= 0) then			-- MYOWNER_ATTACKED_IN
			MyState = CHASE_ST
			MyEnemy = object
			TraceAI ("IDLE_ST -> CHASE_ST : MYOWNER_ATTACKED_IN")
			return 
		end

		object = GetMyEnemy (MyID)		-- ホムの敵のidをobjectへ
		if (object ~= 0) then			-- ATTACKED_IN
			MyState = CHASE_ST
			MyEnemy = object
			TraceAI ("IDLE_ST -> CHASE_ST : ATTACKED_IN")
			return
		end
	end
	local distance = GetDistanceFromOwner(MyID)
	if ( distance > 2 or distance == -1) then		-- MYOWNER_OUTSIGNT_IN
		MyState = FOLLOW_ST
		TraceAI ("IDLE_ST -> FOLLOW_ST")
	return;
	end
--------------------------オートスキル2-------------
	MyState = AMISTR_ST			-- オートスキル処理2、支援スキルの自動かけなおし
----------------------------------------------------
	TraceAI ("OnIDLE_ST -> AMISTR_ST")
end

----------------------------------------------------
-- 追尾処理
----------------------------------------------------
----------------------------------------------------
function	OnFOLLOW_ST ()

	TraceAI ("OnFOLLOW_ST")

	if (GetDistanceFromOwner(MyID) <= 2) then		--  主人とホムの距離が2以下の場合 
		MyState = IDLE_ST				-- 待機状態に
		TraceAI ("FOLLOW_ST -> IDLW_ST")
		return;
	elseif (GetV(V_MOTION,MyID) == MOTION_STAND or GetV(V_MOTION,MyID) == MOTION_MOVE) then		-- ホムの状態が立ち、または移動状態だった場合
		if (GetV(V_MOTION, GetV(V_OWNER,MyID)) == MOTION_MOVE) then	-- 主人が移動状態だったら
			MoveTime2 = GetTick()					-- 現在時刻を移動時の座標更新用タイマー1へ
			if (MoveTime < MoveTime2 - Timer1) then			-- MoveTimeに格納されてるm秒数を過ぎたら移動
				Timer1 = GetTick()				-- 移動した時点での時刻を格納しなおす
				local x,y = GetV(V_POSITION,GetV(V_OWNER,MyID))
				Move (MyID,x,y)
				TraceAI ("FOLLOW_ST -> FOLLOW_ST")
			end
			return;
		else
			local x,y = GetV(V_POSITION,GetV(V_OWNER,MyID))		-- 主人が立ち状態だったら主人のそばに待機
			MoveToOwner (MyID)
			TraceAI ("FOLLOW_ST -> FOLLOW_ST")
			return;
		end
	end

end

----------------------------------------------------
-- 追跡処理
----------------------------------------------------
----------------------------------------------------
function	OnCHASE_ST ()
	TraceAI ("OnCHASE_ST")
---------------------------逃亡判定-----------------
	local MyHP = GetV (V_HP,MyID)
	local MyMaxHP = GetV (V_MAXHP,MyID)
	local HPper = (MyHP / MyMaxHP) * 100
	if (AwayHP >= HPper) then 		-- AwayHP以下だと追跡(攻撃)しない
		MyState = RUNAWAY_ST
		TraceAI ("CHASE_ST -> RUNAWAY_ST")
		return
	end
----------------------------------------------------
	if (true == IsOutOfSight(MyID,MyEnemy)) then	-- Mobが視界から消えたら待機
		MyState = IDLE_ST
		MyEnemy = 0
		MyDestX, MyDestY = 0,0
		TraceAI ("CHASE_ST -> IDLE_ST : ENEMY_OUTSIGHT_IN")
		return
	end
	if (true == IsInAttackSight(MyID,MyEnemy)) then  -- 攻撃範囲に入ったら攻撃
		MyState = ATTACK_ST
		TraceAI ("CHASE_ST -> ATTACK_ST : ENEMY_INATTACKSIGHT_IN")
		return
	end
	local x, y = GetV (V_POSITION,MyEnemy)			-- 敵の座標を代入
	if (MyDestX ~= x or MyDestY ~= y) then			-- 敵の座標がホムの目的座標でない場合
		MyDestX, MyDestY = GetV (V_POSITION,MyEnemy);
		Move (MyID,MyDestX,MyDestY)			-- 敵の方へ接近
		TraceAI ("CHASE_ST -> CHASE_ST : DESTCHANGED_IN")
		return
	end
end
----------------------------------------------------
-- 攻撃処理
----------------------------------------------------
----------------------------------------------------
----------------------------------------------------
-- 攻撃処理
----------------------------------------------------
----------------------------------------------------
function	OnATTACK_ST ()

	TraceAI ("OnATTACK_ST")

	if (true == IsOutOfSight(MyID,MyEnemy)) then	-- Mobが視界から消えたら待機
		MyEnemy = 0
		MySkill = 0
		MyState = IDLE_ST
		TraceAI ("ATTACK_ST -> IDLE_ST")
		return 
	end

	if (MOTION_DEAD == GetV(V_MOTION,MyEnemy)) then   -- Mobが死んだら待機
		MyEnemy = 0
		MySkill = 0
		MyState = IDLE_ST
		TraceAI ("ATTACK_ST -> IDLE_ST")
		return
	end

---------------------------逃亡判定---------------------------------------------
	local MyHP = GetV (V_HP,MyID)
	local MyMaxHP = GetV (V_MAXHP,MyID)
	local HPper = (MyHP / MyMaxHP) * 100
	if (AwayHP >= HPper) then 		-- AwayHP以下だと追跡(攻撃)しない
		MyState = RUNAWAY_ST
		TraceAI ("ATTACK_ST -> RUNAWAY_ST")
		return
	end
--------------------------------------------------------------------------------
	if (false == IsInAttackSight(MyID,MyEnemy)) then  -- Mobが視界に入ったら追いかける
		MyState = CHASE_ST
		MyDestX, MyDestY = GetV (V_POSITION,MyEnemy);
		Move (MyID,MyDestX,MyDestY)
		TraceAI ("ATTACK_ST -> CHASE_ST  : ENEMY_OUTATTACKSIGHT_IN")
		return
	end
----------------------------------------------------
	if (MySkill == 0) then 				-- 使用スキルが指定されていなければ
		
		MyState = AUTOSKILL_ST			-- オートスキル使用
		TraceAI ("ATTACK_ST -> AUTOSKILL_ST")
		Attack (MyID,MyEnemy)

	else						-- スキルが指定されていたらスキル使用
		SkillObject (MyID,MySkillLevel,MySkill,MyEnemy)
		MySkill = 0
	end
----------------------------------------------------
	TraceAI ("ATTACK_ST -> ATTACK_ST  : ENERGY_RECHARGED_IN")
	return
end

----------------------------------------------------
-- 移動処理
----------------------------------------------------
----------------------------------------------------
function	OnMOVE_CMD_ST ()
	TraceAI ("OnMOVE_CMD_ST")
	local x, y = GetV (V_POSITION,MyID)
	if (x == MyDestX and y == MyDestY) then				-- ホムの位置が目的地である場合
		MyState = IDLE_ST					-- 待機状態へ
	end
end
-------------------------------------------------
-- ホムをその場で停止させる(現在未実装)
-- 将来これに手を加えて機能追加させたいなぁ…
-- ケミ待機時に限り、ホムを手動で移動させても戻ってこない(移動先で待機)ような機能を考え中
-- なかなかコードがまとまらないので当分未実装
-------------------------------------------------
-------------------------------------------------
function	OnSTOP_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 OnATTACK_OBJECT_CMD_ST ()

end
-------------------------------------------------
-- 指定座標を攻撃する時のコマンド(使用されていない)
-------------------------------------------------
-------------------------------------------------
function OnATTACK_AREA_CMD_ST ()
	TraceAI ("OnATTACK_AREA_CMD_ST")
	local	object = GetOwnerEnemy (MyID)
	if (object == 0) then							
		object = GetMyEnemy (MyID) 
	end

	if (object ~= 0) then							-- MYOWNER_ATTACKED_IN or ATTACKED_IN
		MyState = CHASE_ST
		MyEnemy = object
		return
	end

	local x , y = GetV (V_POSITION,MyID)
	if (x == MyDestX and y == MyDestY) then			-- DESTARRIVED_IN
			MyState = IDLE_ST
	end
end
-------------------------------------------------
-- 偵察処理(未実装)使えるのか使えないのかよくわからんコマンド
-------------------------------------------------
-------------------------------------------------
function OnPATROL_CMD_ST ()

	TraceAI ("OnPATROL_CMD_ST")

	local	object = GetOwnerEnemy (MyID)		-- 主人の敵IDを代入
	if (object == 0) then				-- 敵が居ない場合
		object = GetMyEnemy (MyID) 		-- ホムの敵を代入
	end

	if (object ~= 0) then				-- 敵が居る場合
		MyState = CHASE_ST			-- その敵を追跡→攻撃
		MyEnemy = object
		TraceAI ("PATROL_CMD_ST -> CHASE_ST : ATTACKED_IN")
		return
	end
	local x , y = GetV (V_POSITION,MyID)
	if (x == MyDestX and y == MyDestY) then			-- ホムが目的地に来たら
		MyDestX = MyPatrolX				-- ホムの目的地座標に偵察座標を設定
		MyDestY = MyPatrolY				-- 同上(どっかで偵察座標の数値をいれないと使えないな…)
		MyPatrolX = x					-- 現在位置を偵察座標へ
		MyPatrolY = y					-- 同上(偵察座標と現在位置の二点をウロウロするってことか…微妙)
		Move (MyID,MyDestX,MyDestY)
	end
end
-------------------------------------------------
-- (未実装)よー分からんコマンド
-------------------------------------------------
-------------------------------------------------
function OnHOLD_CMD_ST ()
	TraceAI ("OnHOLD_CMD_ST")
	if (MyEnemy ~= 0) then				-- 敵がいる場合
		local d = GetDistance2(MyEnemy,MyID)	-- ホムのターゲットの距離をdへ代入
		if (d ~= -1 and d <= GetV(V_ATTACKRANGE,MyID)) then	-- 敵が攻撃範囲内なら
				Attack (MyID,MyEnemy)		-- 攻撃する
		else					-- 敵がいない場合
			MyEnemy = 0;			-- 敵をリセット
		end
		return
	end
	local	object = GetOwnerEnemy (MyID)		-- 主人の敵のIDを代入
	if (object == 0) then				-- 敵が居ない場合
		object = GetMyEnemy (MyID)		-- ホムの敵のIDを代入
		if (object == 0) then			-- 敵が居なければ
			return
		end
	end

	MyEnemy = object				-- 敵IDをセット
end
-------------------------------------------------
-- 指定対象へのスキル使用コマンド(未実装)
-------------------------------------------------
-------------------------------------------------
function OnSKILL_OBJECT_CMD_ST ()
	
end
-------------------------------------------------
-- 指定座標へのスキル使用コマンド(未実装)
-------------------------------------------------
-------------------------------------------------
function OnSKILL_AREA_CMD_ST ()
	TraceAI ("OnSKILL_AREA_CMD_ST")
	local x , y = GetV (V_POSITION,MyID)			-- ホムンクルスの位置を取得
	if (GetDistance(x,y,MyDestX,MyDestY) <= GetV(V_SKILLATTACKRANGE,MyID,MySkill)) then	-- スキル範囲内にホムの目的座標がある場合
		SkillGround (MyID,MySkillLevel,MySkill,MyDestX,MyDestY)		-- -- 設置型スキルを目的座標に使用
		MyState = IDLE_ST
		MySkill = 0
	end
end
-------------------------------------------------
-- 主人追尾
-------------------------------------------------
-------------------------------------------------
function OnFOLLOW_CMD_ST ()

	TraceAI ("OnFOLLOW_CMD_ST")

	local ownerX, ownerY, myX, myY
	ownerX, ownerY = GetV (V_POSITION,GetV(V_OWNER,MyID))		-- 主人の位置を代入
	myX, myY = GetV (V_POSITION,MyID)				-- 自分の位置を代入
	
	local d = GetDistance (ownerX,ownerY,myX,myY)			-- 主人とホムの位置を計算してdへ

	if ( d <= 3) then						-- 3セル以下の距離なら
		return 
	end

	local motion = GetV (V_MOTION,MyID)
	if (motion == MOTION_MOVE) then					-- ホムが移動中の場合
		d = GetDistance (ownerX, ownerY, MyDestX, MyDestY)
		if ( d > 3) then					-- 4セル以上の距離なら
			MoveTime2 = GetTick()					-- 現在時刻を移動時の座標更新用タイマー1へ
			if (MoveTime < MoveTime2 - Timer1) then			-- MoveTimeに格納されてるm秒数を過ぎたら移動
				Timer1 = GetTick()				-- 移動した時点での時刻を格納しなおす
				local x,y = GetV(V_POSITION,GetV(V_OWNER,MyID))
				Move (MyID,x,y)
				TraceAI ("FOLLOW_CMD_ST -> FOLLOW_CMD_ST")
				MyDestX = ownerX			-- ホムの目的地を主人の位置にする
				MyDestY = ownerY			-- 同上
			end
			return
		end
	else								-- ホムが移動以外の動作の時
		MoveToOwner (MyID)					-- 主人のそばへ移動させる
		MyDestX = ownerX					-- ホムの目的地を主人の位置にする
		MyDestY = ownerY					-- 同上
		return
	end
				-- やってることは同じのはずなのに、なんでOnFOLLOW_STと違う記述なんだ…?謎です
end

-------------------------------------------------
-- 主人の敵のIDを得る関数
-------------------------------------------------
-------------------------------------------------
function	GetOwnerEnemy (myid)
	local result = 0				-- 返す敵ID(敵がいない場合0)
	local owner  = GetV (V_OWNER,myid)
	local actors = GetActors ()			-- 視野内のオブジェクト
	local enemys = {}
	local index = 1
	local target
	for i,v in ipairs(actors) do			-- すべての視野内のオブジェクトに対して
-----------------------------主人が殴ってるモンスターも敵とみなす
		if (v == owner) then			-- オブジェクトが主人だった場合
			target = GetV (V_TARGET,v)		-- 主人のターゲットのIDを代入
				if (IsMonster(target) == 1) then	--それがモンスターだったら
				enemys[index] = target		-- そのターゲットを敵とみなす
				index = index+1
				end
		end
----------------------------------------------------
		if (v ~= owner and v ~= myid) then	-- オブジェクトが主人とホム自身でない場合
			target = GetV (V_TARGET,v)	-- ターゲットIDを代入
			if (target == owner) then	-- 主人をタゲっていたら
				if (IsMonster(v) == 1) then		-- それがモンスターだったら
					enemys[index] = v		-- そのオブジェクトを敵とみなす
					index = index+1
				else					-- モンスターで無い場合
					local motion = GetV(V_MOTION,v) -- vの行動を取得
					if (motion == MOTION_ATTACK or motion == MOTION_ATTACK2) then -- 攻撃行動を取っているなら
						enemys[index] = v -- 敵とみなす
						index = index+1
					end
				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		-- 敵として返すIDの候補に入れる
			min_dis = dis		-- 最小距離を更新
		end
	end
	
	return result			-- ホムから最も近い距離にいる召還者の敵IDを返す
end


-------------------------------------------------
-- ホム敵の敵のIDを得る関数(Aタイプ(非先行)とBタイプ(先行)に分かれている)
-------------------------------------------------
-------------------------------------------------
function	GetMyEnemy (myid)
	local result = 0
	result = GetMyEnemyB (myid)		-- Bタイプで敵IDを得る
	return result
end

-------------------------------------------
--  非先攻型 GetMyEnemy
-------------------------------------------
function	GetMyEnemyA (myid)
	local result = 0			-- 返す敵ID(敵がいない場合0)
	local owner  = GetV (V_OWNER,myid)
	local actors = GetActors ()
	local enemys = {}
	local index = 1
	local target

	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			-- オブジェクトが主人のidでもホム自身のidでもない場合
				if (1 == IsMonster(v) and IsNotNoManner( myid, v ) and IsAWAYENEMY(v)) then	-- vがモンスターでタゲが無い、自分か主人をタゲってる、指定Mobでない
					if (3 >= GetDistance2 (myid, v)) then	-- 自分との距離が3の敵を認識(逃亡用)
						enemys[index] = v			-- 敵リストにvのidを追加
						index = index+1
					end
				end
			end
		end
	else
								-- AwayHPより高い場合、ホムはノンアクティブ
		for i,v in ipairs(actors) do
			if (v ~= owner and v ~= myid) then		-- オブジェクトが主人とホム自身でない場合
				target = GetV (V_TARGET,v)			-- オブジェクトのターゲット対象を抽出
				if (target == myid) then			-- ターゲットが自分だったら
					enemys[index] = v			-- 敵リストにvのidを追加
					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		-- 敵として返すIDの候補に入れる
			min_dis = dis		-- 最小距離を更新
		end
	end
	
	return result			-- ホムから最も近い距離にいる召還者の敵IDを返す
end

-------------------------------------------
--  先攻型 GetMyEnemy
-------------------------------------------
function	GetMyEnemyB (myid)
	local result = 0			-- 返す敵ID(敵がいない場合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			-- オブジェクトが主人のidでもホム自身のidでもない場合
				if (1 == IsMonster(v) and IsNotNoManner( myid, v ) and IsAWAYENEMY(v)) then	-- vがモンスターでタゲが無い、自分か主人をタゲってる、指定Mobでない
					if (3 >= GetDistance2 (myid, v)) then	-- 自分との距離が3の敵を認識(逃亡用)
						enemys[index] = v			-- 敵リストにvのidを追加
						index = index+1
					end
				end
			end
		end
	else								-- AwayHPより高い場合、ホムはアクティブ

		for i,v in ipairs(actors) do
			if (v ~= owner and v ~= myid) then	-- オブジェクトが主人のidでもホム自身のidでもない場合
				if (1 == IsMonster(v) and IsNotNoManner( myid, v) and IsNoAttack(v)) then	-- vがモンスターでタゲが無い、自分か主人をタゲってる、指定Mobでない
					if (AttackArea >= GetDistance2 (GetV(V_OWNER,MyID), v)) then	-- 主人との距離がAttackArea以下の場合
						enemys[index] = v				-- 敵リストにvのidを追加
						index = index+1
					end
				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		-- 敵として返すIDの候補に入れる
			min_dis = dis		-- 最小距離を更新
		end
	end
	
	return result			-- ホムから最も近い距離にいる召還者の敵IDを返す
end


-------------------------------------------------
-- メイン関数
-------------------------------------------------
-------------------------------------------------
function AI(myid)

	MyID = myid
	local msg	= GetMsg (myid)			-- クライアントからのコマンドを得る
	local rmsg	= GetResMsg (myid)		-- クライアントからの予約コマンドを得る

	
	if msg[1] == NONE_CMD then						-- コマンドが無い場合で
		if rmsg[1] ~= NONE_CMD then					-- さらに予約コマンドがある場合
			if List.size(ResCmdList) < 10 then		-- 予約コマンドのリストの数が10個以下なら
				List.pushright (ResCmdList,rmsg)	-- 予約コマンドのリストに追加
			end
		end
	else								-- コマンドがある場合は
		List.clear (ResCmdList)					-- 新しいコマンドが入力されたら、予約コマンドは削除する
		ProcessCommand (msg)					-- コマンド処理 
	end

		
	-- 状態処理 
 	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 == MOVE_CMD_ST) then
		OnMOVE_CMD_ST ()
	elseif (MyState == STOP_CMD_ST) then
		OnSTOP_CMD_ST ()
	elseif (MyState == ATTACK_OBJECT_CMD_ST) then
		OnATTACK_OBJECT_CMD_ST ()
	elseif (MyState == ATTACK_AREA_CMD_ST) then
		OnATTACK_AREA_CMD_ST ()
	elseif (MyState == PATROL_CMD_ST) then
		OnPATROL_CMD_ST ()
	elseif (MyState == HOLD_CMD_ST) then
		OnHOLD_CMD_ST ()
	elseif (MyState == SKILL_OBJECT_CMD_ST) then
		OnSKILL_OBJECT_CMD_ST ()
	elseif (MyState == SKILL_AREA_CMD_ST) then
		OnSKILL_AREA_CMD_ST ()
	elseif (MyState == FOLLOW_CMD_ST) then
		OnFOLLOW_CMD_ST ()
	elseif (MyState == RUNAWAY_ST) then
		OnRUNAWAY_ST ()			-- 追加関数(逃亡処理)
	elseif (MyState == AUTOSKILL_ST) then
		OnAUTOSKILL_ST ()		-- 追加関数(オートスキル処理)
	elseif (MyState == AMISTR_ST) then
		OnAMISTR_ST ()		-- 追加関数(アミストル専用)

	end

end



戻る

戻る