戻る

2006/3/17カスタムAIモルティシアVer(先行公開)



※AI.luaにコピペで上書き貼り付けして使用してください※
※使用は自己責任で※

・Mobから逃げ回る処理に移る際、攻撃行動をキャンセルできなかった仕様を修正、
攻撃行動をキャンセルして逃げるようになりました

----------------------------------------
・先行型の時の横殴り防止
・主人とホムの近くに居るMobしか殴らない
・HPが40%未満になったら非先行型に切り替わり、Mobから逃げ回る
・移動の時遅れ気味なホムがまっすぐついてくるように調整
・ホムが主人から離れすぎないよう調整
・草など、反撃しないMobを主人と一緒に殴ってくれる

といったカスタマイズがされています
デフォルトで先行型になっているので、非先行型が好みの方は
function GetMyEnemy (myid)内の GetMyEnemyB (myid) を GetMyEnemyA (myid)に変えて使用してください
----------------------------------------


require "./AI/Const.lua"
require "./AI/Util.lua"		
		
〜省略〜
------------------------------------------
-- 追加分global variable
------------------------------------------
AwayHP					= 40		-- 何%でホムが逃げるか
------------------------------------------
〜省略〜
--------------------------------------------------
-- 基本処理
-------------- state process  --------------------

-- 待機処理
function	OnIDLE_ST ()
	
	TraceAI ("OnIDLE_ST")

	local cmd = List.popleft(ResCmdList)
	if (cmd ~= nil) then		
		ProcessCommand (cmd)	-- 予約コマンド処理 
		return 
	end

	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

	local distance = GetDistanceFromOwner(MyID)
	if ( distance > 2 or distance == -1) then		-- MYOWNER_OUTSIGNT_IN
		MyState = FOLLOW_ST
		TraceAI ("IDLE_ST -> FOLLOW_ST")
		return;
	end

end



-- 主人のところへ戻る
function	OnFOLLOW_ST ()

	TraceAI ("OnFOLLOW_ST")

	if (GetDistanceFromOwner(MyID) <= 2) then		--  DESTINATION_ARRIVED_IN 
		MyState = IDLE_ST
		TraceAI ("FOLLOW_ST -> IDLW_ST")
		return;
	elseif (GetV(V_MOTION,MyID) == MOTION_STAND or GetV(V_MOTION,MyID) == MOTION_MOVE) then
		local x,y = GetV(V_POSITION,GetV(V_OWNER,MyID))
		Move (MyID,x,y)
		TraceAI ("FOLLOW_ST -> FOLLOW_ST")
		return;
	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	-- ENEMY_OUTSIGHT_IN
		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  -- ENEMY_INATTACKSIGHT_IN
		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			-- DESTCHANGED_IN
		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が視界から消えたら待機
		MyState = IDLE_ST
		TraceAI ("ATTACK_ST -> IDLE_ST")
		return 
	end

	if (MOTION_DEAD == GetV(V_MOTION,MyEnemy)) then   -- Mobが死んだら待機
		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 
		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				-- DESTINATION_ARRIVED_IN
		MyState = IDLE_ST
	end
end




function OnSTOP_CMD_ST ()


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)
	if (object == 0) then							
		object = GetMyEnemy (MyID) 
	end

	if (object ~= 0) then							-- MYOWNER_ATTACKED_IN or ATTACKED_IN
		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			-- DESTARRIVED_IN
		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 = GetDistance(MyEnemy,MyID)	-- ホムのターゲットの距離
		if (d ~= -1 and d <= GetV(V_ATTACKRANGE,MyID)) then
				Attack (MyID,MyEnemy)
		else
			MyEnemy = 0;
		end
		return
	end


	local	object = GetOwnerEnemy (MyID)
	if (object == 0) then							
		object = GetMyEnemy (MyID)
		if (object == 0) then						
			return
		end
	end

	MyEnemy = object

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	-- DESTARRIVED_IN
		SkillGround (MyID,MySkillLevel,MySkill,MyDestX,MyDestY)
		MyState = IDLE_ST
		MySkill = 0
	end

end


-- 主人追尾ALT+T
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)

	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セル以上の距離なら
			MoveToOwner (MyID)
			MyDestX = ownerX
			MyDestY = ownerY
			return
		end
	else									-- 他の動作 
		MoveToOwner (MyID)
		MyDestX = ownerX
		MyDestY = ownerY
		return
	end
	
end

-- ホム逃亡処理	
function	OnRUNAWAY_ST ()
	TraceAI ("OnRUNAWAY_ST")

	local MyHP = GetV (V_HP,MyID)
	local MyMaxHP = GetV (V_MAXHP,MyID)
	local HPper = (MyHP / MyMaxHP) * 100
	if (AwayHP >= HPper) then 		-- AwayHP以下だと追跡(攻撃)しない
		
		local distance = GetDistanceFromOwner(MyID)
		if ( distance > 5 or distance == -1) then		-- MYOWNER_OUTSIGNT_IN
			MyState = FOLLOW_ST
			TraceAI ("RUNAWAY -> FOLLOW_ST")
			return;
		end

		local AwayX,AwayY,OwnerX, OwnerY = 0
		AwayX,AwayY = GetV (V_POSITION,MyEnemy);
		OwnerX, OwnerY = GetV (V_POSITION,GetV(V_OWNER,MyID))
		MyX,MyY = GetV(V_POSITION,MyID)
		local distance = GetDistanceFromOwner(MyID)
	
		if (OwnerX > AwayX and OwnerY > AwayY) then	-- 北東へ
			MyDestX = AwayX + 4
			MyDestY = AwayY + 4
			if (MyX > OwnerX + 4) then
				MyDestX = MyDestX - 2
				if (MyY > OwnerY + 4) then
					MyDestY = MyDestY - 2
				end
			end

		elseif (OwnerX > AwayX and OwnerY <= AwayY) then	--南東へ
			MyDestX = AwayX + 4
			MyDestY = AwayY - 4
			if (MyX > OwnerX + 4) then
				MyDestX = MyDestX - 2
				if (MyY < OwnerY - 4) then
					MyDestY = MyDestY + 2
				end
			end

		elseif (OwnerX <= AwayX and OwnerY <= AwayY) then	--南西へ
			MyDestX = AwayX - 4
			MyDestY = AwayY - 4
			if (MyX < OwnerX - 2) then
				MyDestX = MyDestX + 2
				if (MyY < OwnerY - 4) then
					MyDestY = MyDestY + 2
				end
			end

		elseif (OwnerX <= AwayX and OwnerY > AwayY) then	--北西へ
			MyDestX = AwayX - 4
			MyDestY = AwayY + 4
			if (MyX < OwnerX - 4) then
				MyDestX = MyDestX + 2
				if (MyY > OwnerY + 4) then
					MyDestY = MyDestY - 2
				end
			end
		else
			MoveToOwner (MyID)
			TraceAI ("RUNAWAY -> RUNAWAY : END")
			return
		end

		Move (MyID,MyDestX,MyDestY)
		return
	else
		MyState = IDLE_ST
		TraceAI ("RUNAWAY -> IDLE_ST")
		return
	end
end

--

function	GetOwnerEnemy (myid)
	local result = 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)
				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)
			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
			min_dis = dis
		end
	end
	
	return result
end



function	GetMyEnemy (myid)
local result = 0

local MyHP = GetV (V_HP,MyID)
local MyMaxHP = GetV (V_MAXHP,MyID)
local HPper = (MyHP / MyMaxHP) * 100
	if (AwayHP <= HPper) then		-- HPが50%以下になったら非アクティブ化
		result = GetMyEnemyB (myid)
	else
		result = GetMyEnemyA (myid)
	end
return result
end

-------------------------------------------
--  非先攻型 GetMyEnemy
-------------------------------------------
function	GetMyEnemyA (myid)
	local result = 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
-- AwayHP以下だとアクティブに敵認識
	if (AwayHP >= HPper) then

	for i,v in ipairs(actors) do		-- iとvへ、テーブルactorsの値が順番に初期値として入り、iがnilになったらループ脱出
		if (v ~= owner and v ~= myid ) then	-- vの値が主人のidでもホム自身のidでもない場合
			if (1 == IsMonster(v) and IsNotNoManner( myid, v )) then	-- vがモンスターでIsNotNoManner( myid, v )に値が入っている場合
				if (3 >= GetDistance2 (myid, v)) then	-- 自分との距離が3の敵
				
				enemys[index] = v				-- 敵リストにvのidを追加
				index = index+1

				end
			end
		end
	end

	else

	for i,v in ipairs(actors) do		-- iとvへ、テーブルactorsの値が順番に初期値として入り、iがnilになったらループ脱出
		if (v ~= owner and v ~= myid) then	-- vの値が主人のidでもホム自身のidでもない場合
			target = GetV (V_TARGET,v)	-- 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	-- iとvへ、テーブルenemysの値が順番に初期値として入り、iがnilになったらループ脱出
		dis = GetDistance2 (myid,v)	-- 自分をタゲってる敵(v)との距離をdisに代入
		if (dis < min_dis) then		-- 距離が100未満だったら
			result = v		-- resultへvを代入
			min_dis = dis
		end
	end

	return result				-- resultを返す
end

-------------------------------------------
--  先攻型 GetMyEnemy
-------------------------------------------

--
-- 横殴り防止
function IsNotNoManner( myid, id )	-- 攻撃行動中止
	local target = GetV( V_TARGET, id )	-- idのターゲット相手を抽出
	return target == 0 or ( target == myid or target == GetV( V_OWNER, myid ) )	-- タゲが居ない、またはタゲの対象がホム、持ち主(ケミだった場合)、値を返す
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		-- iとvへ、テーブルactorsの値が順番に初期値として入り、iがnilになったらループ脱出
		if (v ~= owner and v ~= myid) then	-- vの値が主人のidでもホム自身のidでもない場合
			if (1 == IsMonster(v) and IsNotNoManner( myid, v ) ) then	-- vがモンスターでIsNotNoManner( myid, v )に値が入っている場合
				if (6 >= GetDistance2 (GetV(V_OWNER,MyID), v)) then	-- 主人との距離が6以下の場合
				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	-- iとvへ、テーブルenemysの値が順番に初期値として入り、iがnilになったらループ脱出
		dis = GetDistance2 (myid,v)	-- 自分をタゲってる敵(v)との距離をdisに代入
		if (dis < min_dis) then		-- 距離が100未満だったら
			result = v		-- resultへvを代入
			min_dis = dis
		end
	end

	return result
end





function AI(myid)

	MyID = myid
	local msg	= GetMsg (myid)			-- command
	local rmsg	= GetResMsg (myid)		-- reserved command

	
	if msg[1] == NONE_CMD then
		if rmsg[1] ~= NONE_CMD then
			if List.size(ResCmdList) < 10 then
				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 ()

	end

end




戻る

戻る