do local function CalcStep( now, dest ) if dest - now == 0 then return 1 -- 直線移動の際に障害物をよける end return ( dest - now ) / math.abs( dest - now ) end local function IsMovable( myid, x, y ) -- マップデータを見て移動可能か判断 local margin = 3 -- 回り道をする余裕 local posx, posy = GetV( V_POSITION, myid ) local stepx = CalcStep( posx, x ) -- 目的地への歩数 1 または -1 を求める local stepy = CalcStep( posy, y ) local moved = {} -- すでに移動した座標の登録 local function IsValidCell( nx, ny ) -- 有効なセルか local enabled = MAP_ENABLED or 1 -- maplua版なら定数、mobdata版なら1が移動可能セル if not( MAP and MAP[ny] and MAP[ny][nx] and MAP[ny][nx] == enabled ) then return false end if nx < math.min( posx, x ) - margin or nx > math.max( posx, x ) + margin then -- 範囲外 return false end if ny < math.min( posy, y ) - margin or ny > math.max( posy, y ) + margin then return false end return true end local function IsWideCell( nx, ny ) -- 1マス周辺に障害物がないか local cells = { { nx, ny + 1 }, -- 時計周り { nx + 1, ny + 1 }, { nx + 1, ny }, { nx + 1, ny - 1 }, { nx, ny - 1 }, { nx - 1, ny - 1 }, { nx - 1, ny }, { nx - 1, ny + 1 }, } for i,v in ipairs( cells ) do if not IsValidCell( v[1], v[2] ) then return false end end return true end local nowx, nowy = posx, posy local function MoveToCell( nx, ny ) if not IsValidCell( nx, ny ) then return false end local key = nx..","..ny if moved[ key ] then -- 移動済みセルには移動しない return false end moved[ key ] = true -- 移動済みセルに登録 nowx, nowy = nx, ny return true end MoveToCell( nowx, nowy ) -- 移動済みセルに登録 local function IsOverHorz() -- 目標セルよりオーバー(迂回)しているか return ( nowx - x ) * stepx > 0 end local function IsOverVert() return ( nowy - y ) * stepy > 0 end while true do if nowx == x and nowy == y then -- 目的地到達 return true -- elseif IsOverHorz() and IsOverVert() then -- 正反対の距離に移動してしまった -- return false elseif IsOverHorz() and ( MoveToCell( nowx - stepx, nowy ) or MoveToCell( nowx, nowy + stepy ) ) then elseif IsOverVert() and ( MoveToCell( nowx, nowy - stepy ) or MoveToCell( nowx + stepx, nowy ) ) then elseif nowy == y and math.abs( nowx - x ) == 1 and MoveToCell( nowx + stepx, nowy ) then -- 目標セルの隣りで、なおかつオーバーしていない elseif nowx == x and math.abs( nowy - y ) == 1 and MoveToCell( nowx, nowy + stepy ) then elseif IsWideCell( nowx + stepx, nowy ) and MoveToCell( nowx + stepx, nowy ) then -- 開けているほうのセルへ移動 elseif IsWideCell( nowx, nowy + stepy ) and MoveToCell( nowx, nowy + stepy ) then -- 開けているほうのセルへ移動 -- 本当は IsWideCount とかでもっとも開けているセルを選出して移動してもいいが、 -- あまり厳密にやりすぎると Move 関数がスタックするような入り組んだセルにも true を返してしまうのがジレンマ elseif MoveToCell( nowx + stepx, nowy ) then -- 東(-1=西)に移動 elseif MoveToCell( nowx, nowy + stepy ) then -- 北(-1=南)に移動 elseif MoveToCell( nowx - stepx, nowy ) then -- 西(-1=東)に移動 elseif MoveToCell( nowx, nowy - stepy ) then -- 南(-1=北)に移動 else -- 詰まった return false end end end local function GetCurrentMapCode() -- 選択マップコードを取得 local chunk = loadfile("./AI/USER_AI/MAP/current_mapcode.lua") if chunk then return chunk() end return nil end local function LoadMapFile( file ) local t = GetTick() local map = loadfile("./AI/USER_AI/MAP_OLD/"..file..".lua") if map then map() -- ファイルがあれば読み込む else TraceAI("Load Map Error: "..file ) end local t2 = GetTick() TraceAI( "Load Map: "..file.." "..tostring( t2 - t ).." msec" ) end local raw_GetActors = GetActors local actors = {} local mapcode local function MapFilter() local mc = GetCurrentMapCode() -- マップをまだ読み込んでないか、マップコードが変更されたらマップファイル読み込み if mapcode == nil or mc ~= mapcode then MAP = nil -- GC対象へ collectgarbage() -- マップを読み込む前に不要メモリを捨てる if mc then -- マップコードが指定されているなら LoadMapFile( mc ) mapcode = mc end end local src = raw_GetActors() local count = 0 actors = {} for i,v in ipairs( src ) do if not MAP or IsMovable( MyID, GetV( V_POSITION, v ) ) then count = count + 1 actors[ count ] = v -- TraceAI("Visible Actor: "..GetV( V_HOMUNTYPE, v )) else -- TraceAI("Invisible Actor: "..GetV( V_HOMUNTYPE, v )) end end end ROAIPlus.setEvent( ROAIPlus.EVENT_BEGIN, MapFilter ) GetActors = function() return actors end end