<?xml version="1.0" encoding="utf-8"?><waypoints>
<onLoad>

--=== V 2.3.1 ===--
Ed - extended to use a set of attacks instead of a simple non-aoe/mage routine.

--=== User Options ===--
When_Finished = "end" -- "end" to end script, "relog" to log next character and "waypointfilename" to load that waypointfile.
guardianrockspirit = "Guardian Rock Spirit" -- change name with language here, id doesn't work at the moment.

--====================--

local attackdistance
if player.Class1 == CLASS_SCOUT or player.Class1 == CLASS_PRIEST or player.Class1 == CLASS_DRUID then
	attackdistance = 50
else
	attackdistance = 22
end

local orderlist = {6,12,18,24,30,36,35,34,33,32,31,25,19,13,7,1,2,3,4,5}
local attackSkills = {"KNIGHT_WHIRLWIND_SHIELD", "ALL_FULL_MOON_CLEAVE", "KNIGHT_DISARMAMENT"}
local attackAOE = {3, 3, 1}
local attackCooldown = {6,20,0}
local lastUsedTime = {os.time(), os.time(), os.time()}
local listsize = #orderlist

--returns the details of the first available attack skill
function getAvailableAttack()
	local skillCount = #attackSkills;
	local count = 0;
	
	repeat
		count = count + 1;
	until ((count > skillCount) or (os.time() > (lastUsedTime[count] + attackCooldown[count])));
	
	if (count > skillCount) then return nil, nil; end;
	return count, attackAOE[count];
end

function useAttack(idx)
	player:cast(attackSkills[idx]);
	lastUsedTime[idx] = os.time();
end

--=== Table numbering system ===--
--[[
	1 7 13 19 25 31
	2 8 14 20 26 32
	3 9 15 21 27 33
	4 10 16 22 28 34
	5 11 17 23 29 35
	6 12 18 24 30 36
* -- entrance to room.
]]
function trashhp()
	local target = player:getTarget()
	if target.Id == 101489 then
		if 10 > target.HP then
			player:clearTarget();
			return false
		end
		if arg1.Name == "MAGE_FLAME" then 
			return false
		end			
	end
end

--=== Turn off looting, wastes time ===--
settings.profile.options.LOOT = false
settings.profile.options.TARGET_LEVELDIF_ABOVE = "15" -- Need to try to kill anything in there or no point.
settings.profile.options.TARGET_LEVELDIF_BELOW = "60" --trash is lvl 15 which people won't allow for in profile.
settings.profile.events.onPreSkillCast = function() return trashhp() end -- deals with trash hp.

function checkRelog()
	if When_Finished == "relog" then
		sendMacro("}LoginNextToon=true;a={")
		sendMacro("Logout();");
		waitForLoadingScreen();
		loadPaths("survival");
	elseif When_Finished == "end" then
		error("Ending script",2)
	elseif When_Finished == "stop" then
	else
		if not string.find(When_Finished,".", 1, true) then
			When_Finished = When_Finished .. ".xml"
		end
		local filename = getExecutionPath() .. "/waypoints/" .. When_Finished
		local file, err = io.open(filename, "r");
		if file then
			file:close();
			loadPaths(When_Finished)
		else
			error("'When_Finished' option is invalid",0)
		end
	end
end

--=== Function to sort tables, at angle ===--
local function SEsize(_x, _z)
   local X1 = 2622.1403808594
   local Z1 = 2900.1105957031
   local X2 = 2471.7895507813
   local Z2 = 2954.833984375

   return math.floor(((_x-X1)*(Z2-Z1)-(X2-X1)*(_z-Z1))/math.sqrt((X2-X1)^2 + (Z2-Z1)^2) + 0.5)
end

local function NEsize(_x, _z)
   local X1 = 2471.7895507813
   local Z1 = 2954.833984375
   local X2 = 2526.5126953125
   local Z2 = 3105.1848144531

   return math.floor(((_x-X1)*(Z2-Z1)-(X2-X1)*(_z-Z1))/math.sqrt((X2-X1)^2 + (Z2-Z1)^2) + 0.5)
end

function addToNE(_x, _z, _s)
   return _x + (_s * 0.9397), _z - (_s * 0.3420)
end

function addToSE(_x, _z, _s)
   return _x + (_s * 0.3420), _z + (_s * 0.9397)
end

function GetAttackPosition(_x, _z)
   local SEvalue = SEsize(_x, _z)
   local NEvalue = NEsize(_x, _z)
   if 1 > SEvalue then -- nw edge
      return addToSE(_x, _z, - attackdistance)
   elseif SEvalue > 159 then -- se edge
      return addToSE(_x, _z, attackdistance)
   elseif 1 > NEvalue then -- sw edge
      return addToNE(_x, _z, - attackdistance)
   elseif NEvalue > 159 then -- ne edge
      return addToNE(_x, _z, attackdistance)
   end
end



--=== Create table of tiles ===--
function createTileTable()

   tiles = {}

   local objectList = CObjectList();
   objectList:update();
   local objSize = objectList:size()

   for i = 0,objSize do
      local obj = objectList:getObject(i);
      if obj.Id == 111811 or obj.Id == 111812 then
         table.insert(tiles, table.copy(obj))
      end
   end

   -- Sort function
   local function sortfunc(a,b)
      if SEsize(a.X,a.Z) == SEsize(b.X,b.Z) then
         return NEsize(b.X,b.Z) > NEsize(a.X,a.Z)
      else
         return SEsize(b.X,b.Z) > SEsize(a.X,a.Z)
      end
   end
   
   -- Sort tiles
   table.sort(tiles, sortfunc)
end

--=== look for indicator that the tile is clickable ===--
function clicktile(address)
	local tmp = memoryReadRepeat("int", getProc(), address + addresses.pawnAttackable_offset) or 0;
	if bitAnd(tmp,0x8) then
		return true
	else
		return false
	end
end
	
--=== look for indicator that the chest has loot ===--
function clickchest(address)
	local chest = memoryReadRepeat("byte", getProc(), address + 0x2F0) or 0
	if chest ~= 0 then
		return true
	else
		return false
	end
end	

--=== Get into Survival Zone ===--
local zoneid = RoMScript("GetZoneID()")
if zoneid ~= 351 then -- not in Survival
	local Malatina = GetIdName(111813)
	-- Try to find Malatina and teleport in
	if player:target_NPC(Malatina) then
		if 50 > player.Level and (player.Level2 >= 50 or player.Level3 >= 50) then
			-- Wait for user to change class
			cprintf(cli.yellow,"If you want to earn Phirius Shells, change to your 50+ class before continuing.\n")
			player:sleep()
		end
		sendMacro("ChoiceOption(1);");
		yrest(2000)
		sendMacro("ChoiceOption(1);");
		if not waitForLoadingScreen(30) then
			print("Failed to teleport into Survival")
			checkRelog()
		end
	else
		print("You are too far from Malatina")
		checkRelog()
	end
end
	

--=== First mobs to kill ===--
function trashmelee()
	local attackIndex, attackAOE = getAvailableAttack();
	local i = attackAOE or 1;
	
	repeat
		local tile = tiles[orderlist[i]]
		teleport(GetAttackPosition(tile.X,tile.Z))
		yrest(500)
		local trash = player:findNearestNameOrId(101489)
		if trash then
			local distance = distance(player.X, player.Z, trash.X, trash.Z)
			if (attackdistance * 2) > distance then
				player:target(trash)
				if (attackIndex) then
					useAttack(attackIndex);
				else
					player:fight();
				end;
				
				yrest(500)
				player:clearTarget();
			end
			
			i = i + attackAOE-1;
			attackIndex, attackAOE = getAvailableAttack();
			attackAOE = attackAOE or 1;
			i = i + attackAOE;
		else
			i = i + 1;
		end
	until (i >= listsize)
	spawnsmelee()
end

--=== Kill spawns melee ===--
function spawnsmelee()
	local attackIndex, attackAOE = getAvailableAttack();
	local i = attackAOE or 1;
	
	repeat
		local tile = tiles[orderlist[i]]
		teleport(GetAttackPosition(tile.X,tile.Z))
		yrest(500);
		local spawn = player:findNearestNameOrId(guardianrockspirit)
		yrest(500)
		if spawn then
			local distance = distance(player.X, player.Z, spawn.X, spawn.Z)
			player:target(spawn) 
			if (attackIndex) then
				useAttack(attackIndex);
			else
				player:fight();
			end;
			
			i = i + attackAOE-1;
			attackIndex, attackAOE = getAvailableAttack();
			attackAOE = attackAOE or 1;
			i = i + attackAOE;
		else
			printf("Something wrong, name incorrect.\n")
		end
		if player.Battling then
			local _enemy = player:findEnemy(true,nil)
			if _enemy then
				player:target(_enemy.Address);
				player:fight()
			end
		end				
	until (i >= listsize)

	breaktiles()
end	

--=== Start of tiles function ===--
function breaktiles()	
	if player.Class1 == CLASS_MAGE then
		changeProfileSkill("MAGE_PURGATORY_FIRE" , "AutoUse", false)
	end
	--=== First run of tiles ===--
	orderlist = {1,4,7,10,13,16,19,22,25,28,31,34,2,5,8,11,14,17,20,23,26,29,32,35,3,6,9,12,15,18,21,24,27,30,33,36}
	for i = 1,36 do
		local tile = tiles[orderlist[i]]
		repeat
		yrest(200)
		local _enemy = player:findEnemy()
		local distance = distance(player.X, player.Z, _enemy.X, _enemy.Z)
		if _enemy and 100 > distance then
			player:target(_enemy.Address);
			player:fight()
		end			
		if not RoMScript("TimeKeeperFrame:IsVisible()") then
			checkRelog()
		end	
		fly()
		teleport(tile.X+2,tile.Z+2,18)
		rest(100)
		player:target_Object(tile.Id, nil, false, true, clicktile);
		until clicktile(tile.Address) == false
	end
	
	--=== get any left over tiles as a double check ===--
	repeat
	local tile = player:findNearestNameOrId("Treasure Tile", nil, clicktile)
		if tile then
			if player.Battling then
				local _enemy = player:findEnemy(true,nil)
				if _enemy then
					player:target(_enemy.Address);
					player:fight()
				end
			end		
			teleport(tile.X,tile.Z,14)
			player:target_Object({111811,111812}, nil, false, true, clicktile);
		end
	until tile == nil
	chests()
end

--=== Open chests ===--
function chests()
	local chests = {}
	local objectList = CObjectList();
	objectList:update();
	local objSize = objectList:size()

	for i = 0,objSize do
		local obj = objectList:getObject(i);
		if obj.Id == 111956 then
			table.insert(chests, table.copy(obj))
		end
	end	

	for k,v in pairs(chests) do
		
		if not RoMScript("TimeKeeperFrame:IsVisible()") then
			checkRelog()
		end
		if clickchest(v.Address) == true then
			teleport(v.X+10,v.Z+10,15)
			repeat
				player:target_Object(v.Id, nil, nil, true);
			until clickchest(v.Address) ~= true
		end
	end
	checkRelog()
end
</onLoad>
	<!-- #  1 --><waypoint x="2519" z="2593" y="9">	
		speed(70)
		local joker = GetIdName(111814)	
		player:target_NPC(joker);
		sendMacro("ChoiceOption(2);");
	</waypoint>
	<!-- #  2 --><waypoint x="2546" z="2681" y="9" type="TRAVEL">	</waypoint>
	<!-- #  3 --><waypoint x="2586" z="2789" y="9" type="TRAVEL">	</waypoint>
	<!-- #  4 --><waypoint x="2606" z="2843" y="9" type="TRAVEL">
		createTileTable() -- do it here as you can't see the pawns until you start the event.
		local trash = player:findNearestNameOrId(101489)  -- check for trash
		local spawns = player:findNearestNameOrId(101652) -- check for spawns
		local tiles =  player:findNearestNameOrId("Treasure Tile", nil, clicktile) -- check if any tiles need opening
		
		if trash then -- add in options for aoe and ranged here
			trashmelee() -- clears trash within melee range
		end
		
		if spawns then
			spawnsmelee() -- kill spawns within melee range
		end
		
		if trash == nil and spawns == nil and tiles ~= nil then
			breaktiles() -- start breaking tiles
		end
		
		if tiles == nil then
			chests() -- open chests
		end
	</waypoint>

</waypoints>