-- LUA Script - precede every function and global member with lowercase name of script + '_main'
--DESCRIPTION: smallg's fish following waypoint script 
--DESCRIPTION: [SWIMSPEED=100] how fast the fish moves
--DESCRIPTION: [ALERTRANGE=500] how far the fish will detect the player from 
--DESCRIPTION: if attackrange = 0 then fish will flee from player when detected
--DESCRIPTION: [ATTACKRANGE=80] fish must be within this range to start attacking the player
--DESCRIPTION: [DAMAGE=1]
--DESCRIPTION: [WATERHEIGHT=500] player is in water when below this height (default = 500)
--DESCRIPTION: [ANIMATED!=0]
--DESCRIPTION: [SWIMANIM=1] swimming animation number
--DESCRIPTION: [ATTACKANIM=2] attacking animation number

fishstate = {}
local angle = {}
local maxplayerdistance = {}
local swim_speed_max = {}
local followheight = {}
local pathindex, pointindex, pathdirection = {}, {}, {}
isfish = {}
g_fish = {}
function fish_properties(e, swimspeed, alertrange, attackrange, damage, waterheight, animated, swimanim, attackanim)
	local f = g_fish[e] 
	f.swimspeed = swimspeed
	f.alertrange = alertrange
	f.attackrange = attackrange
	f.damage = damage
	f.waterheight = waterheight
	f.animated = animated
	f.swimanim = swimanim
	f.attackanim = attackanim
	swim_speed_max[e] = f.swimspeed
end 
 
function fish_init(e)
	g_fish[e] = {}
	local f = g_fish[e]
	f.swimspeed = 100
	f.alertrange = 500
	f.attackrange = 80
	f.damage = 1
	f.waterheight = 500
	f.animated = 0
	f.swimanim = 1
	f.attackanim = 2
	
	if math.random(1,10) < 10 then 
		f.attackrange = 0
	end 
	angle[e] = 0
	fishstate[e] = "get path"
	swim_speed_max[e] = f.swimspeed
	isfish[e] = e
end
 
function fish_main(e)
	local function AngleToPoint(e,x,z)
		if g_Entity[e] ~= nil and x > 0 and z > 0 then
			local destx = x - g_Entity[e]['x']
			local destz = z - g_Entity[e]['z']
			local angle = math.atan2(destx,destz)
			angle = angle * (180.0 / math.pi)
			--angle = angle + math.random(-1,1)
			if angle < 0 then
				angle = 360 + angle
			elseif angle > 360 then
				angle = angle - 360
			end
			return angle
		end
	end
	local function GetPlayerFlatDistance(e)
		if g_Entity[e] ~= nil then
		local disx = g_Entity[e]['x'] - g_PlayerPosX
		local disz = g_Entity[e]['z'] - g_PlayerPosZ
		return math.sqrt(disx^2 + disz^2)
		end
	end
	local function GetPlayerFlatDistanceToPoint(x,z)
		local disx = g_PlayerPosX - x
		local disz = g_PlayerPosZ - z
		return math.sqrt(disx^2 + disz^2)
	end
	local function GetFlatDistance(e,x,z)
		if g_Entity[e] ~= nil then
		local disx = g_Entity[e]['x'] - x
		local disz = g_Entity[e]['z'] - z
		return math.sqrt(disx^2 + disz^2)
		end
	end
	--PromptLocal(e,fishstate[e])
	--TextCenterOnX(50,80,3,g_PlayerPosY)
	local f = g_fish[e]
	--Prompt(g_PlayerPosY)
	CollisionOff(e)	
	if fishstate[e] == "get path" then
		local PathIndex = -1
		local PathPointIndex = -1
		local pClosest = 999999
		for pa = 1, AIGetTotalPaths(), 1 do
			for po = 1 , AIGetPathCountPoints(pa), 1 do
				local pDX = g_Entity[e]['x'] - AIPathGetPointX(pa,po)
				local pDZ = g_Entity[e]['z'] - AIPathGetPointZ(pa,po)
				local pDist = (pDX*pDX)+(pDZ*pDZ)
				if pDist < pClosest and pDist < 12500*12500 then
					pClosest = pDist
					PathIndex = pa
					PathPointIndex = po
				end
			end -- po
		end -- pa
		if PathIndex > -1 then
			pathindex[e] = PathIndex
			pointindex[e] = PathPointIndex
			pathdirection[e] = 1
			fishstate[e] = "swim"
			followheight[e] = math.random(100,150)
			angle[e] = 0
		else 
			fishstate[e] = "idle"
		end  
	elseif fishstate[e] == "idle" then 
		if g_PlayerPosY < f.waterheight then 
			if GetPlayerFlatDistance(e) < f.alertrange then
				StartTimer(e)
				fishstate[e] = "alerted"
			end
		end 
	elseif fishstate[e] == "swim" then 	
		if f.animated == 1 then 
			if g_Entity[e]['animating'] ~= f.swimanim then 
				SetAnimation(f.swimanim)
				LoopAnimation(e)
				ModulateSpeed(e,1)				
			end 
		end 
		local destx = AIPathGetPointX(pathindex[e],pointindex[e])
		local destz = AIPathGetPointZ(pathindex[e],pointindex[e])
		angle[e] = AngleToPoint(e,destx, destz)
		SetRotation(e,0,angle[e],0)
		--AIEntityGoToPosition(g_Entity[e]['obj'],ai_patrol_x[e],ai_patrol_z[e])
		MoveForward(e,f.swimspeed)
		local ty = GetTerrainHeight(g_Entity[e]['x'], g_Entity[e]['z'])
		--Prompt(ty)
		ty = ty + followheight[e]
		local heightdif = 0
		if g_Entity[e]['y'] < ty then 
			heightdif = ty - g_Entity[e]['y']
			heightdif = heightdif * 1
		elseif g_Entity[e]['y'] > ty then 
			heightdif = g_Entity[e]['y'] - ty 
			heightdif = heightdif * -1
		end 
		MoveUp(e,heightdif)
		local tDistX = g_Entity[e]['x'] - destx
		local tDistZ = g_Entity[e]['z'] - destz
		local DistFromPath = (tDistX*tDistX)+(tDistZ*tDistZ)
		if DistFromPath < 100000 then
			followheight[e] = math.random(100,150)
			angle[e] = 0
			f.swimspeed = swim_speed_max[e] * math.random(0.75,1.25)
			if pathdirection[e] == 1 then
				pointindex[e] = pointindex[e] + 1
				local pathnodes = AIGetPathCountPoints(pathindex[e])
				if pointindex[e] > pathnodes then
					pointindex[e] = pathnodes - 1
					pathdirection[e] = -1
				end
			else
				pointindex[e] = pointindex[e] - 1
				if pointindex[e] < 1 then
					pointindex[e] = 2
					pathdirection[e] = 1
				end       
			end
		end
		if g_PlayerPosY < f.waterheight then 
			local pfdist = GetPlayerFlatDistance(e)
			if pfdist < f.alertrange then
				fishstate[e] = "alerted"
			end
		end  
	elseif fishstate[e] == "alerted" then 
		maxplayerdistance[e] = GetPlayerFlatDistance(e)
		if f.attackrange > 0 then 
			fishstate[e] = "alert"
		else 
			fishstate[e] = "flee"
		end 
	elseif fishstate[e] == "flee" then
		if pathindex[e] ~= nil then 
			local tdist = 0
			local pathnodes = AIGetPathCountPoints(pathindex[e])
			for i = 1, pathnodes do 
				local tdist2 = GetPlayerFlatDistanceToPoint(AIPathGetPointX(pathindex[e], i), AIPathGetPointZ(pathindex[e], i))
				if tdist2 > tdist then 
					tdist = tdist2
					pointindex[e] = i 
				end 
			end 
			angle[e] = AngleToPoint(e, AIPathGetPointX(pathindex[e], pointindex[e]), AIPathGetPointZ(pathindex[e], pointindex[e]))
		else 
			angle[e] = AngleToPoint(e, g_PlayerPosX, g_PlayerPosZ)+math.random(90,270)
		end 
		fishstate[e] = "fleeing"
	elseif fishstate[e] == "fleeing" then 
		SetRotation(e,0,angle[e],0)		
		if f.animated == 1 then 
			if g_Entity[e]['animating'] ~= f.swimanim then 
				SetAnimation(f.swimanim)
				LoopAnimation(e)				
			end 
		end 
		local ty = GetTerrainHeight(g_Entity[e]['x'], g_Entity[e]['z'])
		--Prompt(ty)
		ty = ty + followheight[e]
		local heightdif = 0
		if g_Entity[e]['y'] < ty then 
			heightdif = ty - g_Entity[e]['y']
			heightdif = heightdif * 1
		elseif g_Entity[e]['y'] > ty then 
			heightdif = g_Entity[e]['y'] - ty 
			heightdif = heightdif * -1
		end 
		MoveUp(e,heightdif)
		ModulateSpeed(e,8)
		MoveForward(e,f.swimspeed * 8)
		if GetFlatDistance(e, AIPathGetPointX(pathindex[e], pointindex[e]), AIPathGetPointZ(pathindex[e], pointindex[e])) < 100000 then 
			if pathindex[e] ~= nil then 
				fishstate[e] = "swim"
			else 
				fishstate[e] = "get path"
			end
		end 
	elseif fishstate[e] == "alert" then	
		ModulateSpeed(e,1.5)
		if f.animated == 1 then 
			if g_Entity[e]['animating'] ~= f.swimanim then 
				SetAnimation(f.swimanim)
				LoopAnimation(e)				
			end 
		end 
		local pfdist = GetPlayerFlatDistance(e)
		local turnspeed = 30 * (1-(pfdist / maxplayerdistance[e]))
		RotateToPlayerSlowly(e,turnspeed)		
		local heightdif = 0
		if g_PlayerPosY < g_Entity[e]['y'] then 
			heightdif = (g_Entity[e]['y'] - g_PlayerPosY) * -0.5
		elseif g_PlayerPosY > g_Entity[e]['y'] then 
			heightdif = (g_PlayerPosY - g_Entity[e]['y']) * 0.5
		end
		MoveUp(e,heightdif)
		if pfdist < f.attackrange then 
			fishstate[e] = "attack"
		elseif pfdist > f.alertrange * 1.3 or g_PlayerPosY > f.waterheight then 
			fishstate[e] = "get path"			
		else 
			MoveForward(e,f.swimspeed * 1.5)
		end 	 
	elseif fishstate[e] == "attack" then		
		if f.animated == 1 then 
			if g_Entity[e]['animating'] ~= f.attackanim then 				
				SetAnimation(f.attackanim)
				PlayAnimation(e)				
			end 
		else 
			StartTimer(e)
		end 
		PlaySound(e,1)	
		HurtPlayer(e,f.damage)
		ModulateSpeed(e,1)
		fishstate[e] = "attacking"
	elseif fishstate[e] == "attacking" then 
		local heightdif = 0
		if g_PlayerPosY < g_Entity[e]['y'] then 
			heightdif = (g_Entity[e]['y'] - g_PlayerPosY) * -0.5
		elseif g_PlayerPosY > g_Entity[e]['y'] then 
			heightdif = (g_PlayerPosY - g_Entity[e]['y']) * 0.5
		end
		MoveUp(e,heightdif)
		RotateToPlayer(e)		
		local pfdist = GetPlayerFlatDistance(e)
		if pfdist > f.attackrange then
			MoveForward(e,swim_speed_max[e]*0.25)
		elseif pfdist < f.attackrange then 
			MoveForward(e,swim_speed_max[e]*-0.25)
		end
		if (f.animated == 1 and g_Entity[e]['animating'] == 0) or (f.animated == 0 and GetTimer(e) > 250) then 
			if pathindex[e] ~= nil then 
				fishstate[e] = "swim" 
			else 
				fishstate[e] = "get path"
			end 
		end 	
	elseif fishstate[e] == "got away" then 
		if pathindex[e] ~= nil then 
			fishstate[e] = "swim" 
		else 
			fishstate[e] = "get path"
		end 
	else 
		StopAnimation(e)
		g_Entity[e]['animating'] = -1
	end --fishstate	 
	--PromptLocal(e,fishstate[e])
	--CollisionOn(e)
end --main
 
function fish_exit(e)
 
end
 
