function CPlayer:loot() if( settings.profile.options.LOOT ~= true and settings.profile.options.LOOT_SIGILS ~= true) then if( settings.profile.options.DEBUG_LOOT) then cprintf(cli.yellow, "[DEBUG] don't loot reason: settings.profile.options.LOOT ~= true and settings.profile.options.LOOT_SIGILS ~= true\n"); end; return end if settings.profile.options.LOOT == true then repeat -- 'repeat' block to 'break' from 'if' statement if( self.TargetPtr == 0 ) then if( settings.profile.options.DEBUG_LOOT) then cprintf(cli.yellow, "[DEBUG] don't loot reason: self.TargetPtr == 0\n"); end; break end -- aggro and not loot in combat if( self.Battling and settings.profile.options.LOOT_IN_COMBAT ~= true ) and self:findEnemy(true, nil, evalTargetDefault) then self:clearTarget() cprintf(cli.green, language[178]); -- Loot skiped because of aggro return end self:update(); local target = self:getTarget(); if( target == nil or target.Address == 0 ) then if( settings.profile.options.DEBUG_LOOT) then cprintf(cli.yellow, "[DEBUG] don't loot reason: target == nil or target.Address == 0\n"); end; break; end local dist = distance(self.X, self.Z, target.X, target.Z); local hf_x = self.X local hf_z = self.Z; local lootdist = 100; -- Set to combat distance; update later if loot distance is set if( settings.profile.options.COMBAT_TYPE == "ranged" ) then lootdist = settings.profile.options.COMBAT_DISTANCE; end if( settings.profile.options.LOOT_DISTANCE ) then lootdist = settings.profile.options.LOOT_DISTANCE; end if( dist > lootdist ) then -- only loot when close by cprintf(cli.green, language[32]); -- Target too far away; not looting. cprintf(cli.green, "Distanz is "..dist.." to be exact \n"); break end local function looten() -- "attack" is also the hotkey to loot, strangely. --[[local hf_attack_key; if( settings.profile.hotkeys.MACRO ) then hf_attack_key = "MACRO"; cprintf(cli.green, language[31], hf_attack_key , dist); -- looting target. RoMScript("UseSkill(1,1);"); else hf_attack_key = getKeyName(settings.profile.hotkeys.ATTACK.key); cprintf(cli.green, language[31], hf_attack_key , dist); -- looting target. keyboardPress(settings.profile.hotkeys.ATTACK.key); end]] Attack() -- yrest(settings.profile.options.LOOT_TIME + dist*15); -- dist*15 = rough calculation of how long it takes to walk there -- inventory:updateSlotsByTime(settings.profile.options.LOOT_TIME + dist*15); local maxWaitTime = settings.profile.options.LOOT_TIME + dist*15 -- dist*15 = rough calculation of how long it takes to walk there local startWait = getTime() while target.Lootable == true and deltaTime(getTime(), startWait) < maxWaitTime do yrest(50) target:update() end --[[ -- Wait for character to finish standing local starttime = os.clock() self:update() while self.Stance ~= 0 and 2 > (os.clock() - starttime) do yrest(50) self:update() end ]]-- end local function lootenAgain() Attack() -- yrest(settings.profile.options.LOOT_TIME + dist*15); -- dist*15 = rough calculation of how long it takes to walk there -- inventory:updateSlotsByTime(settings.profile.options.LOOT_TIME + dist*15); local maxWaitTime = settings.profile.options.LOOT_TIME -- dist*15 = rough calculation of how long it takes to walk there local startWait = getTime() while ( target ~= nil and target.Address ~= 0 ) and deltaTime(getTime(), startWait) < maxWaitTime do yrest(50) target:update() end -- Wait for character to finish standing local starttime = os.clock() self:update() --[[while self.Stance ~= 0 and 0.3 > (os.clock() - starttime) do yrest(50) self:update() end ]]-- end --yrest(1000); self:update(); target:update(); if target.Lootable then looten(); end; -- check for loot problems to give a noob mesassage self:update(); local target = self:getTarget(); dist = distance(self.X, self.Z, target.X, target.Z); if( dist > 50 and -- We would need to be further away to be able to move to the target --self.X == hf_x and -- we didn't move, seems attack key is not defined --self.Z == hf_z and ( target ~= nil and target.Address ~= 0 ) ) then -- death mob disapeared? -- and = less ghost hunting cprintf(cli.green, language[100]); -- We didn't move to the loot!? -- second loot try? if( type(settings.profile.options.LOOT_AGAIN) == "number" and settings.profile.options.LOOT_AGAIN > 0 and ( target ~= nil and target.Address ~= 0 ) ) then yrest(settings.profile.options.LOOT_AGAIN); lootenAgain(); yrest(100); cprintf(cli.green,"We tried to loot again \n"); end end; -- rnd pause from 2-6 sec after loot to look more human if( settings.profile.options.LOOT_PAUSE_AFTER > 0 ) then self:restrnd( settings.profile.options.LOOT_PAUSE_AFTER,1,2); end; -- Close the booty bag. RoMScript("BootyFrame:Hide()"); until true end -- 'end' ends the 'if' statement local function sigilNameMatch(_name) if settings.profile.options.SIGILS_IGNORE_LIST == nil then return true -- collect all sigils end for sigil in string.gmatch(";"..settings.profile.options.SIGILS_IGNORE_LIST,"[,;]([^,;]*)") do if string.match(sigil,"^'.*'$") then sigil = string.match(sigil,"^'(.*)'$") end if sigil == _name then return false -- ignore the sigil end end return true -- not in ignore list. Don't ignore. end local function getNearestSigil() local nearestSigil = nil; local obj = nil; local objectList = CObjectList(); objectList:update(); for i = 0,objectList:size() do obj = objectList:getObject(i); if( obj ~= nil ) and ( obj.Type == PT_SIGIL ) and sigilNameMatch(obj.Name) then local dist = distance(self.X, self.Z, obj.X, obj.Z); if( nearestSigil == nil and dist < settings.profile.options.LOOT_DISTANCE ) then nearestSigil = obj; else if( dist < settings.profile.options.LOOT_DISTANCE and dist < distance(self.X, self.Z, nearestSigil.X, nearestSigil.Z) ) then -- New nearest sigil found nearestSigil = obj; end end end end return nearestSigil; end if settings.profile.options.LOOT_SIGILS == true or (settings.profile.options.LOOT == true and settings.profile.options.LOOT_SIGILS == nil) then -- Pick up all nearby sigils self:clearTarget(); self:update(); local sigil = getNearestSigil(); --while( sigil ) do if( sigil ) then local dist = distance(self.X, self.Z, self.Y, sigil.X, sigil.Z, sigil.Y); local angle = math.atan2(sigil.Z - self.Z, sigil.X - self.X); local yangle = math.atan2(sigil.Y - self.Y, ((sigil.X - self.X)^2 + (sigil.Z - self.Z)^2)^.5 ); local nY = self.Y + math.sin(yangle) * (dist + 15); local hypotenuse = (1 - math.sin(yangle)^2)^.5 local nX = self.X + math.cos(angle) * (dist + 15) * hypotenuse; local nZ = self.Z + math.sin(angle) * (dist + 15) * hypotenuse; printf("Picking up sigil \"%s\"\n",sigil.Name) self:moveTo( CWaypoint(nX, nZ, nY), true ); yrest(300); self:update(); sigil = getNearestSigil(); end end end local lootIgnoreList = {}; local lootIgnoreListPos = 0; local lootIgnore = 0; local lootIgnoreCounter = 0; function evalTargetLootable(address, target) if not target then target = CPawn(address); end -- Check if lootable if not ( target.Lootable ) then return false; end -- Check if in lootIgnoreList for __, addr in pairs(lootIgnoreList) do if target.Address == addr then return false end end -- Check height difference if( math.abs(target.Y - player.Y) > 45 ) then return false; end -- check distance to target local dist = distance(player.X, player.Z, player.Y, target.X, target.Z, target.Y); local lootdist = 100; -- Set to combat distance; update later if loot distance is set if( settings.profile.options.COMBAT_TYPE == "ranged" ) then lootdist = settings.profile.options.COMBAT_DISTANCE; end if( settings.profile.options.LOOT_DISTANCE ) then lootdist = settings.profile.options.LOOT_DISTANCE; end if( dist > lootdist ) then -- only loot when close by return false end -- check target distance to path against MAX_TARGET_DIST local wpl; -- this is the waypoint list we're using local V; -- this is the point we will use for distance checking if( player.Returning ) then wpl = __RPL; else wpl = __WPL; end if (__WPL:getMode() == "waypoints") and #__WPL.Waypoints > 0 then local pA = wpl.Waypoints[wpl.LastWaypoint] local pB = wpl.Waypoints[wpl.CurrentWaypoint] V = getNearestSegmentPoint(player.X, player.Z, pA.X, pA.Z, pB.X, pB.Z); else V = CWaypoint(player.X, player.Z); -- Distance check from player in wander mode end -- use a bounding box first to avoid sqrt when not needed (sqrt is expensive) if( target.X > (V.X - lootdist) and target.X < (V.X + lootdist) and target.Z > (V.Z - lootdist) and target.Z < (V.Z + lootdist) ) then if( distance(V.X, V.Z, target.X, target.Z) > lootdist ) then if( settings.profile.options.DEBUG_LOOT) then cprintf(cli.yellow, "unlooted monster dist > lootdist") end return false; -- he is not a valid target end; else -- must be too far away if( settings.profile.options.DEBUG_LOOT) then cprintf(cli.yellow, "unlooted monster dist > lootdist") end return false; end return true end function CPlayer:lootAll() if( settings.profile.options.LOOT ~= true ) then if( settings.profile.options.DEBUG_LOOT) then cprintf(cli.yellow, "[DEBUG] don't loot all reason: settings.profile.options.LOOT ~= true\n"); end; return end if( settings.profile.options.LOOT_ALL ~= true ) then if( settings.profile.options.DEBUG_LOOT) then cprintf(cli.yellow, "[DEBUG] don't loot all reason: settings.profile.options.LOOT_ALL ~= true\n"); end; return end -- Warn user if they still have 'lootbodies()' userfunction installed. if type(lootBodies) == "function" then cprintf(cli.yellow,"The userfunction 'lootBodies()' is obsolete and might interfere with the bots 'lootAll()' function. Please delete the 'addon_lootbodies.lua' file from the 'userfunctions' folder.\n") end while true do -- Check if inventory is full. We don't loot if inventory is full. if inventory:itemTotalCount(0) == 0 then if( settings.profile.options.DEBUG_LOOT) then cprintf(cli.yellow, "[DEBUG] don't loot all reason: inventory is full\n"); end; return end self:update() if( self.Battling and self:findEnemy(true,nil,evalTargetDefault)) then break end self:findEnemyList(false, nil, evalTargetLootable); local Lootable = self:findLootable() if Lootable == nil then break end self:target(Lootable) self:update() if self.TargetPtr ~= 0 then -- Target's still there. self:loot() if self:findEnemy(true, nil, evalTargetDefault) then -- not looting because of aggro return end yrest(50) Lootable:update(); if Lootable.Lootable == true then -- Failed to loot. Add to ignore list if lootIgnoreListPos > settings.profile.options.LOOT_IGNORE_LIST_SIZE then lootIgnoreListPos = 1 end local lootIgnoreCounter = 0; while( (Lootable.Lootable == true) and (lootIgnoreCounter < 1)) do player:lootAll() yrest(100) Lootable:update(); lootIgnoreCounter = lootIgnoreCounter + 1; end if Lootable.Lootable == true then lootIgnoreList[lootIgnoreListPos] = Lootable.Address; end end end end end local LootableList = {}; -- Returns nil if nothing found, otherwise returns a pawn function CPlayer:findEnemyList(aggroOnly, _id, evalFunc, ignore) ignore = ignore or 0; local aggroOnly = aggroOnly or false; local bestScore = 0; local obj = nil; local objectList = CObjectList(); objectList:update(); if( type(evalFunc) ~= "function" ) then evalFunc = function (unused) return true; end; end -- The 'max' values that each scoring sub-part uses local SCORE_DISTANCE = 60; -- closer = more score; actually score will usually be less than half local SCORE_AGGRESSIVE = 80; -- aggressive = score local SCORE_ATTACKING = 100; -- attacking = score local SCORE_HEALTHPERCENT = 75; -- lower health = more score for i = 0,objectList:size() do obj = objectList:getObject(i); if( obj ~= nil ) then local inp = memoryReadRepeat("int", getProc(), obj.Address + addresses.pawnAttackable_offset) or 0; if not bitAnd(inp,0x4000000) then -- Invisible/attackable? if( obj.Type == PT_MONSTER and (_id == obj.Id or _id == nil) and obj.Address ~= ignore) then local dist = distance(self.X, self.Z, obj.X, obj.Z); local pawn = CPawn(obj.Address); local _target = pawn:getTarget(); if( evalFunc(pawn.Address, pawn) == true ) then if( distance(self.X, self.Z, pawn.X, pawn.Z ) < settings.profile.options.LOOT_DISTANCE and (( (pawn.TargetPtr == self.Address or (pawn.TargetPtr == self.PetPtr and self.PetPtr ~= 0) or _target.InParty == true ) and aggroOnly == true) or aggroOnly == false) ) then local currentScore = 0; currentScore = currentScore + ( (settings.profile.options.LOOT_DISTANCE - dist) / settings.profile.options.LOOT_DISTANCE * SCORE_DISTANCE ); --currentScore = currentScore + ( (pawn.MaxHP - pawn.HP) / pawn.MaxHP * SCORE_HEALTHPERCENT ); -- if( pawn.TargetPtr == self.Address ) then currentScore = currentScore + SCORE_ATTACKING; end; -- if( pawn.Aggressive ) then -- currentScore = currentScore + SCORE_AGGRESSIVE; -- end; --if _target.InParty == true then currentScore = currentScore + 5000 end if(table.contains(LootableList, obj) == false)then table.insert(LootableList,{targetpt = obj, score = currentScore}) bestScore = currentScore; end end end end end end end table.sort(LootableList,List_Sort); return LootableList; end function CPlayer:findLootable() local distm = 0; repeat if( LootableList[1] ~= nil ) then obj = LootableList[1].targetpt; obj:update(); table.remove(LootableList, 1); distm = distance(self.X, self.Z,self.Y, obj.X, obj.Z,obj.Y); else return nil; end until distm < settings.profile.options.LOOT_DISTANCE; return obj; end function table.contains(table, element) for _, value in pairs(table) do if value == element then return true end end return false end function List_Sort(a , b) if(a.score > b.score)then return true else return false end end