Signup Now
Page 5 of 5 FirstFirst ... 345
Results 41 to 42 of 42
  1. #41
    Free User
    Join Date
    Sep 2016
    Posts
    27
    Reputation
    10
    Rep Power
    0
    superb script, however since the new summons have come out, i summon my Thundergiant and the rune thrower constantly tries to throw on him, resulting in me getting a message "you may not attack your own summon", what am i doing wrong ? or does script need to be updated ?

  2. #42
    Free User seebaa's Avatar
    Join Date
    Dec 2013
    Posts
    19
    Reputation
    10
    Rep Power
    0
    why bug?

    error in Persistent script Spells Attack:
    [" return dmg >= hp"]:Spells Attack:734 attempt to compare number with nil
    stack traceback:
    [" if wouldDieToAStrike(c) then"]:Spells Attack:742 in function [" return function()"]:Spells Attack:721
    [" status = spell.shooter(currentMasks[spell.name],..."]:Spells Attack:886 in function [" local function tryCastSpell(spell..."]:Spells Attack:883
    [" tryCastSpell(unpack(pconfig))"]:Spells Attack:915 in user script


    init start
    -----------------------------------------------------------------------
    -------------------------------- CONFIG -------------------------------
    -----------------------------------------------------------------------
    Config = {
    pvpsafe = true, -- Do you want to avoid hitting other players with spells?
    buffersize = 2, -- How far outside of the spell's aoe to check for players?
    ignoreParty = true, -- Is it ok to hit party members? Enable if you want to team hunt.

    multiFloor = false, -- Check for players on other floors?
    blacklistIds = {469, 1959, 1960}, -- Enable multi floor checks regardless of above settings if one of these items are on the screen. Add stuff like stairs and rope holes.

    manaPotion = "ultimate mana potion", -- Which mana potion to use?

    useStrongStrikes = true, -- Do you want to use strong strikes?
    turnForWaves = true, -- Do you want to wave in directions other than the on your are facing?
    spells = {
    {name = "exevo gran mas vis", count = 9},
    {name = "exevo gran mas vis", monsters = {"devourer", "blood Beast", "rot elemental", "Glooth Blob"}, count = 7, minhp = 20},
    {name = "thunderstorm rune", count = 5, monsters = {"devourer", "blood Beast", "rot elemental", "Quara Predator Scout", "Quara Hydromancer Scout", "quara pincher scout", "quara constrictor scout", "Glooth Blob"}},
    {name = "exevo vis hur", monsters = {"devourer", "blood Beast", "rot elemental", "Quara Predator Scout", "Quara Hydromancer Scout", "quara pincher scout", "quara constrictor scout", "Glooth Blob"}, count = 3},
    {name = "thunderstorm rune", count = 2, monsters = {"devourer", "blood Beast", "rot elemental", "Quara Predator Scout", "Quara Hydromancer Scout", "quara pincher scout", "quara constrictor scout", "Glooth Blob"}},
    {name = "sudden death rune", monsters = {"devourer"}},
    }
    }

    -----------------------------------------------------------------------
    ---------------------------- END OF CONFIG ----------------------------
    -----------------------------------------------------------------------
    local NORTH, EAST, SOUTH, WEST = 'n', 'e', 's', 'w'
    local lastPlayerSeenTime = 0
    -- All masks must be quadratical. You cannot leave out the zeros.
    -- Also, all masks must have sizes that are odd numbers.
    masks = {

    ball = {
    {0,0,1,1,1,0,0},
    {0,1,1,1,1,1,0},
    {1,1,1,1,1,1,1},
    {1,1,1,1,1,1,1},
    {1,1,1,1,1,1,1},
    {0,1,1,1,1,1,0},
    {0,0,1,1,1,0,0},
    },

    ["exevo gran mas flam"] = {
    {0,0,0,0,0,1,0,0,0,0,0},
    {0,0,0,1,1,1,1,1,0,0,0},
    {0,0,1,1,1,1,1,1,1,0,0},
    {0,1,1,1,1,1,1,1,1,1,0},
    {0,1,1,1,1,1,1,1,1,1,0},
    {1,1,1,1,1,1,1,1,1,1,1},
    {0,1,1,1,1,1,1,1,1,1,0},
    {0,1,1,1,1,1,1,1,1,1,0},
    {0,0,1,1,1,1,1,1,1,0,0},
    {0,0,0,1,1,1,1,1,0,0,0},
    {0,0,0,0,0,1,0,0,0,0,0},
    },

    ["exevo gran mas vis"] = {
    {0,0,0,0,0,0,1,0,0,0,0,0,0},
    {0,0,0,0,0,1,1,1,0,0,0,0,0},
    {0,0,0,0,1,1,1,1,1,0,0,0,0},
    {0,0,0,1,1,1,1,1,1,1,0,0,0},
    {0,0,1,1,1,1,1,1,1,1,1,0,0},
    {0,1,1,1,1,1,1,1,1,1,1,1,0},
    {1,1,1,1,1,1,1,1,1,1,1,1,1},
    {0,1,1,1,1,1,1,1,1,1,1,1,0},
    {0,0,1,1,1,1,1,1,1,1,1,0,0},
    {0,0,0,1,1,1,1,1,1,1,0,0,0},
    {0,0,0,0,1,1,1,1,1,0,0,0,0},
    {0,0,0,0,0,1,1,1,0,0,0,0,0},
    {0,0,0,0,0,0,1,0,0,0,0,0,0},
    },

    ["exevo gran mas frigo"] = {
    {0,0,0,0,0,1,0,0,0,0,0},
    {0,0,0,0,1,1,1,0,0,0,0},
    {0,0,0,1,1,1,1,1,0,0,0},
    {0,0,1,1,1,1,1,1,1,0,0},
    {0,1,1,1,1,1,1,1,1,1,0},
    {1,1,1,1,1,1,1,1,1,1,1},
    {0,1,1,1,1,1,1,1,1,1,0},
    {0,0,1,1,1,1,1,1,1,0,0},
    {0,0,0,1,1,1,1,1,0,0,0},
    {0,0,0,0,1,1,1,0,0,0,0},
    {0,0,0,0,0,1,0,0,0,0,0},
    },

    ["exevo gran mas tera"] = {
    {0,0,0,0,0,0,1,0,0,0,0,0,0},
    {0,0,0,0,1,1,1,1,1,0,0,0,0},
    {0,0,0,1,1,1,1,1,1,1,0,0,0},
    {0,0,1,1,1,1,1,1,1,1,1,0,0},
    {0,1,1,1,1,1,1,1,1,1,1,1,0},
    {0,1,1,1,1,1,1,1,1,1,1,1,0},
    {1,1,1,1,1,1,1,1,1,1,1,1,1},
    {0,1,1,1,1,1,1,1,1,1,1,1,0},
    {0,1,1,1,1,1,1,1,1,1,1,1,0},
    {0,0,1,1,1,1,1,1,1,1,1,0,0},
    {0,0,0,1,1,1,1,1,1,1,0,0,0},
    {0,0,0,0,1,1,1,1,1,0,0,0,0},
    {0,0,0,0,0,0,1,0,0,0,0,0,0},
    },

    -- Waves should be entered as their NORTH direction.
    -- The extra zeros in the other directions are needed for the
    -- rotations to work properly.

    -- Also frigo hur and gran frigo hur
    ["exevo flam hur"] = {
    {0,0,0,1,1,1,0,0,0,},
    {0,0,0,1,1,1,0,0,0,},
    {0,0,0,0,1,0,0,0,0,},
    {0,0,0,0,1,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,},
    },

    ["exevo vis hur"] = {
    {0,0,0,0,1,1,1,0,0,0,0,},
    {0,0,0,0,1,1,1,0,0,0,0,},
    {0,0,0,0,0,1,0,0,0,0,0,},
    {0,0,0,0,0,1,0,0,0,0,0,},
    {0,0,0,0,0,1,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    },
    ["exevo vis lux"] = {
    {0,0,0,0,0,1,0,0,0,0,0,},
    {0,0,0,0,0,1,0,0,0,0,0,},
    {0,0,0,0,0,1,0,0,0,0,0,},
    {0,0,0,0,0,1,0,0,0,0,0,},
    {0,0,0,0,0,1,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,},
    },
    ["exevo gran vis lux"] = {
    {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
    },

    -- Note that the strike mask will be centered over your look position rather than yourself.
    strikes = {
    -- Strikes dont get any buffer around them, and are treated sort of like waves in that the mask changes depending on which direction you're facing.
    {0,0,1,0,0,},
    {0,1,1,1,0,},
    {1,1,1,1,1,},
    {0,1,1,1,0,},
    {0,0,0,0,0,},
    }
    }

    masks["exevo frigo hur"] = masks["exevo flam hur"]
    masks["exevo gran frigo hur"] = masks["exevo vis hur"]

    -- Positions are stored in one dimensional tables by first converting them to numbers.
    -- Note that for the sake of this script the z-coordinate is irrelevant.
    -- Also, the function is linear. The number for a sum of two positions is the sum of the numbers for each position.
    local function posToNum(x, y)
    return 100000*x+y
    end
    -- Inverse of posToNum.
    local function numToPos(n)
    local y = n % 100000
    local x = (n - y) / 100000
    return x, y
    end

    -- Constants representing what to check for in a converted mask
    local PLAYERS, PLAYERS_AND_MONSTERS = 0, 1

    -- Converts a spell mask to a hashset containing the numerical offsets.
    -- Every position within *margin* squares from a 1 in the original mask is added to the set.
    local function convertMask(mask, margin, marginValue)
    local marginValue = marginValue or PLAYERS
    -- Node that the size of a mask must be an odd number since all spells are symmetrical.
    local xmid, ymid = math.ceil(#mask / 2), math.ceil(#mask[1] / 2)

    local convertedMask = {}

    local function fillMask(margin, value)
    for y = 1, #mask do
    for x = 1, #mask[y] do
    if mask[y][x] == 1 then
    for oy = y - margin, y + margin do
    for ox = x - margin, x + margin do
    -- The masks are stored with indexes starting at 1,
    -- but in-game we have negative offsets for squares above or to the left of the character.
    convertedMask[posToNum(ox - xmid, oy - ymid)] = value
    end
    end
    end
    end
    end
    end

    -- First write the pvp-safe area
    if margin > 0 then
    fillMask(margin, marginValue)
    end
    -- Then overwrite the area in which we check for monsters
    fillMask(0, PLAYERS_AND_MONSTERS)

    return convertedMask
    end

    local function getSurroundings(multifloor, blacklist)
    local monsters, players, shootables = {}, {}, {}

    if not multifloor then
    -- First check for blacklisted ids and enable multifloor if one is found
    for x = $posx - 7, $posx + 7 do
    for y = $posy - 5, $posy + 5 do
    local tile = gettile(x, y, $posz)
    for i = 1, tile.itemcount do
    -- Also treat blacklisted ids as players, since players may arrive
    if blacklist[tile.item[i].id] then multifloor = true end
    end
    end
    end
    end
    local maxzdiff = multifloor and 1 or 0

    local xdiff = Config.pvpsafe and math.max(2, 4 - Config.buffersize) or 4
    local ydiff = Config.pvpsafe and math.max(1, 3 - Config.buffersize) or 4
    -- First filter out the walkable positions since we cannot shoot on top of walls
    for x = $posx - xdiff, $posx + xdiff do
    for y = $posy - ydiff, $posy + ydiff do
    if tileshootable(x, y, $posz) and tileclickable(x, y, $posz) then
    shootables[posToNum(x, y)] = true
    end
    end
    end

    -- Add our creature tiles
    foreach creature c 'm' do
    if c.posz == $posz then
    if c.issummon then
    players[posToNum(c.posx, c.posy)] = c
    else
    monsters[posToNum(c.posx, c.posy)] = c
    end
    end
    end

    -- Add our player tiles
    foreach creature c 'p' do
    local isPartyMember = c.party >= 3 and c.party <= 10
    if math.abs(c.posz - $posz) <= maxzdiff and not (Config.ignoreParty and isPartyMember) and
    c.name ~= $name then
    players[posToNum(c.posx, c.posy)] = c
    end
    end

    return monsters, players, shootables
    end

    local function creatures(monsters, targetMonsters, filter)
    local validMonsters = {}
    local cogx, cogy, numMonsters = 0, 0, 0
    for pos, c in pairs(monsters) do
    if (not targetMonsters or targetMonsters[c.name:lower()]) and
    (not filter or filter(c))
    then
    validMonsters[pos] = c
    cogx = cogx + c.posx
    cogy = cogy + c.posy
    numMonsters = numMonsters + 1
    end
    end

    return validMonsters, {x = cogx/numMonsters, y = cogy/numMonsters}
    end

    local function getScore(pos, mask, monsters, players, finalcheck, pvpsafe)
    local score = 0
    local effectedMonsters = {}
    local monsters = monsters or {}

    for offset, TYPE in pairs(mask) do
    if pvpsafe and players[pos + offset] then
    return -1
    elseif TYPE == PLAYERS_AND_MONSTERS and monsters[pos + offset] then
    score = score + 1
    table.insert(effectedMonsters, monsters[pos + offset])
    end
    end
    if not finalcheck or finalcheck(effectedMonsters) then
    return score
    else
    return 0
    end
    end

    local function getBestBallPos(monsters, players, shootables, mask, monsterNames, pvpsafe, filter, finalcheck)
    local monsters, cog = creatures(monsters, monsterNames, filter)
    local cx, cy = cog.x, cog.y

    -- Ties are broken by preference for positions close to the monster's center of gravity
    local function getTieScore(num)
    local x, y = numToPos(num)
    return math.abs(cx-x) + math.abs(cy-y)
    end

    -- Then find the best one among the shootables
    local bestScore, bestTieScore, bestPos
    for pos, _ in pairs(shootables) do
    local score = getScore(pos, mask, monsters, players, finalcheck, pvpsafe)
    local tieScore = getTieScore(pos)
    if not bestScore or score > bestScore or (score == bestScore and tieScore < bestTieScore) then
    bestScore, bestTieScore, bestPos = score, tieScore, pos
    end
    end
    return bestPos, bestScore
    end

    -- For printing purposes
    local SUCCESS, SKIP, RETRY = 0, 1, 2
    statusString = {
    [SUCCESS] = "SUCCESS",
    [SKIP] = "SKIP",
    [RETRY] = "RETRY"
    }
    -- Possible return values for a function that tries to shoot a spell
    local STRIKE, SINGLE_TARGET_RUNE, BALL, UE, WAVE = 0, 1, 2, 3, 4
    local typeString = {
    [STRIKE] = "STRIKE",
    [SINGLE_TARGET_RUNE] = "SINGLE TARGET RUNE",
    [BALL] = "BALL",
    [UE] = "UE",
    [WAVE] = "WAVE",
    }

    local function getType(spell)
    if type(spell) == 'number' then
    spell = Item.GetName(spell)
    end

    spell = spell:lower()

    for _, name in ipairs({"thunderstorm", "avalanche", "great fireball", "stone shower"}) do
    if spell:match(name) then
    return BALL
    end
    end

    if spell:match("exori") then
    return STRIKE
    end

    if spell:match("exevo gran mas") then
    return UE
    end

    if spell:match("exevo") then
    return WAVE
    end

    return SINGLE_TARGET_RUNE
    end

    local function rotateMask(mask, dir)
    local ymax, xmax = #mask, #mask[1]

    local function rotate(x, y)
    if dir == NORTH then
    return x, y
    elseif dir == EAST then
    return (ymax - y) + 1, x
    elseif dir == SOUTH then
    return x, (ymax - y) + 1
    elseif dir == WEST then
    return y, x
    end
    end

    local newMask = {}
    for y = 1, ymax do
    table.insert(newMask, {})
    for x = 1, xmax do
    table.insert(newMask[y], 0)
    end
    end

    for y = 1, ymax do
    for x = 1, xmax do
    if mask[y][x] == 1 then
    local nx, ny = rotate(x, y)
    newMask[ny][nx] = 1
    end
    end
    end

    return newMask
    end

    local function getMask(spell, TYPE, margin)
    if TYPE == WAVE then
    if not masks[spell] then print("Unknown spell: " .. spell) end
    local convertedMasks = {}
    for _, dir in ipairs({NORTH, EAST, SOUTH, WEST}) do
    convertedMasks[dir] = convertMask(rotateMask(masks[spell], dir), margin)
    end
    return convertedMasks
    elseif TYPE == STRIKE then
    local convertedMasks = {}
    for _, dir in ipairs({NORTH, EAST, SOUTH, WEST}) do
    convertedMasks[dir] = convertMask(rotateMask(masks.strikes, dir), 0)
    end
    return convertedMasks
    end

    local base = masks.strikes
    if TYPE == BALL then
    base = masks.ball
    elseif TYPE == UE then
    if not masks[spell] then print("Unknown spell: " .. spell) end
    base = masks[spell]
    end
    return convertMask(base, margin)
    end

    local mana = {
    ["exevo gran mas vis"] = 600,
    ["exevo gran mas flam"] = 1100,
    ["exevo gran mas tera"] = 700,
    ["exevo gran mas frigo"] = 1050,

    ["exori vis"] = 20,
    ["exori flam"] = 20,
    ["exori tera"] = 20,
    ["exori frigo"] = 20,
    ["exori mort"] = 20,
    ["exori moe ico"] = 20,

    ["exori gran vis"] = 60,
    ["exori gran flam"] = 60,
    ["exori gran tera"] = 60,
    ["exori gran frigo"] = 60,

    ["exori max frigo"] = 100,
    ["exori max frigo"] = 100,
    ["exori max frigo"] = 100,
    ["exori max frigo"] = 100,

    ["exori min flam"] = 6,
    ["exori amp vis"] = 60,

    ["exevo flam hur"] = 25,
    ["exevo vis hur"] = 170,
    ["exevo frigo hur"] = 25,
    ["exevo gran frigo hur"] = 170,

    ["exevo vis lux"] = 40,
    ["exevo gran vis lux"] = 110,
    }

    function string:titlecase()
    return self:gsub("(%a)([%w_']*)", function(first, rest) return first:upper()..rest:lower() end)
    end

    local function convertCategory(c)
    local monsters = {}
    foreach settingsentry e 'Targeting/Creatures' do
    local name = getsetting(e, 'Name')
    local cat = getsetting(e, 'Category')
    if not name:find('category') and (cat ~= '' and c:find(cat)) then
    monsters[name:lower()] = true
    end
    end
    return monsters
    end


    function convertSpellConfig(arg)
    local TYPE = getType(arg.name)
    local spell = arg.name:lower()

    local monsters
    -- Build up the target list, if there is one
    if arg.monsters then
    if type(arg.monsters) == "string" then
    monsters = convertCategory(arg.monsters)
    else
    monsters = {}
    for _, name in ipairs(arg.monsters) do
    monsters[name:lower()] = true
    end
    end
    end

    -- Range and mana settings.
    -- Could be rewritten to use spellinfo, but
    -- I wanted to reuse as much as possible of my old Xeno code.
    local range = spell == "exori amp vis" and 5 or 3
    local mana = mana[spell] or 0

    -- Filters determine wheter a given creature is valid or not.
    -- Generally this will inspect the creatures health percentage
    local filter
    if arg.minhp or arg.maxhp then
    local minhp = arg.minhp or 0
    local maxhp = arg.maxhp or 100
    filter = function(c)
    return c.hppc < maxhp and c.hppc > minhp
    end
    end

    -- Final checks determine whether a group of creatures are valid.
    -- For example, check that an ava cast hits at least one Demon Skeleton, otherwise fall through and try a GFB instead.
    local finalcheck
    if arg.atLeastOne then
    local atLeastOneMonsters = {}
    for _, name in ipairs(arg.atLeastOne) do
    atLeastOneMonsters[name] = true
    end

    finalcheck = function(creatures)
    for _, c in ipairs(creatures) do
    if atLeastOneMonsters[c.name] then return true end
    end
    return false
    end
    end

    return {
    spell = spell,
    type = TYPE,
    monsters = monsters,
    range = range,
    mana = mana,
    count = function() return arg.count end,
    enabled = function() return true end,
    filter = filter,
    finalcheck = finalcheck,
    }
    end

    local opposite = {
    [NORTH] = SOUTH,
    [SOUTH] = NORTH,
    [EAST] = WEST,
    [WEST] = EAST,
    }

    local function tryTurnAway()
    local dirs = {}
    foreach creature c 'ps' do
    if math.max(math.abs(c.posx - $posx), math.abs(c.posy - $posy)) <= 3 then
    if c.posx - $posx > 0 then
    dirs[EAST] = true
    elseif c.posx - $posx < 0 then
    dirs[WEST] = true
    end

    if c.posy - $posy > 0 then
    dirs[SOUTH] = true
    elseif c.posy - $posy < 0 then
    dirs[NORTH] = true
    end
    end
    end

    for _, dir in ipairs({NORTH, EAST, SOUTH, WEST}) do
    if dirs[dir] and not dirs[opposite[dir]] then return turn(opposite[dir]) end
    end
    end

    local function getLookPos()
    if $self.dir == NORTH then
    return $posx, $posy - 1
    elseif $self.dir == EAST then
    return $posx + 1, $posy
    elseif $self.dir == SOUTH then
    return $posx, $posy + 1
    elseif $self.dir == WEST then
    return $posx - 1, $posy
    end
    end

    local currentMasks = {}
    local function updateMasks()
    local spells = {}
    for _, data in ipairs(Config.spells) do
    local spell = data.name:lower()
    currentMasks[spell] = getMask(spell, getType(spell), Config.buffersize)
    end

    currentMasks["exori flam"] = getMask("exori flam", STRIKE, Config.buffersize)
    end
    updateMasks()

    lastRuneCast = os.clock()
    function getShooterFunc(config, blacklist)
    if config.type == UE then
    return function(_, monsters, players)
    local spell = config.spell
    if not config.enabled() then return SKIP end

    -- UE's cant be checked precisely, so dont cast them when weve seen players around lately.
    if Config.pvpsafe and (os.clock() - lastPlayerSeenTime) < 10 then
    return SKIP
    end
    -- Return instantly if the spell is on cooldown or we dont have mana
    if cooldown(spell) > 2000 or $mp < config.mana then
    return SKIP
    elseif cooldown(spell) > 0 then
    return RETRY
    end

    local mask = currentMasks[spell]
    local monsters = creatures(monsters, config.monsters, config.filter)
    local score = getScore(posToNum($posx, $posy), mask, monsters, players, config.finalcheck, Config.pvpsafe)
    -- If we found enough creatures, try casting, else skip the spell
    -- Also, don't UE if there's more monsters standing just outside the area
    if score >= config.count() then
    cast(spell)
    return cooldown(spell) == 0 and RETRY or SUCCESS
    else
    return SKIP
    end
    end
    elseif config.type == BALL then
    return function(mask, monsters, players, shootables)
    --print(config.spell, tostring(config.enabled()))
    if not config.enabled() then return SKIP end
    -- Skip if we dont have that rune
    if itemcount(config.spell) == 0 then return SKIP end
    if cooldown("exori flam") > 0 then return RETRY end
    -- Find the best position to shoot the rune
    local numpos, score = getBestBallPos(monsters, players, shootables, mask, config.monsters, Config.pvpsafe, config.filter, config.finalcheck)
    -- Casting on self is more efficient, so always compare it with the best pos
    local monsters = creatures(monsters, config.monsters, config.filter)
    local selfScore = getScore(posToNum($posx, $posy), mask, monsters, players, config.finalcheck, Config.pvpsafe)
    -- If we found a good position)
    if numpos and score >= config.count() then
    local x, y = numToPos(numpos)
    lastRuneCast = os.clock()
    pausewalking(1000)
    if $fasthotkeys and selfScore + 0 >= score and selfScore >= config.count() then
    useoncreature(itemid(config.spell), $self)
    else
    useitemon(itemid(config.spell), 0, ground(x, y, $posz))
    end
    pausewalking(100 + $ping)

    if cooldown("exori flam") ~= 0 then
    return SUCCESS
    else
    return RETRY
    end
    end
    return SKIP
    end
    elseif config.type == WAVE then
    return function(mask, monsters, players)
    if not config.enabled() then return SKIP end

    -- Skip if the spell is on a long cooldown or we dont have mana
    if cooldown(config.spell) > 2000 or $mp < config.mana then return SKIP end
    local pos = posToNum($posx, $posy)

    local monsters = creatures(monsters, config.monsters, config.filter)
    -- Determine the best direction to wave
    local bestDir, bestScore
    for _, dir in ipairs({NORTH, EAST, SOUTH, WEST}) do
    local score = getScore(pos, mask[dir], monsters, players, config.finalcheck, Config.pvpsafe)

    -- All directions must be pvp-safe for us to wave, cause we can fail to turn.
    if score == -1 then return SKIP end

    if (Config.turnForWaves or dir == $self.dir) and (not bestScore or score > bestScore) then
    bestDir, bestScore = dir, score
    end
    end

    -- Skip if we couldn't find any sufficiently good directions
    if not bestDir or bestScore < config.count() then
    return SKIP
    else
    pausewalking(1000)
    -- Note that for waves we prefer to skip the spell rather than retry if something goes wrong
    if $self.dir ~= bestDir then
    turn(bestDir)
    waitping()
    end
    if $self.dir ~= bestDir then return end
    cast(config.spell)
    pausewalking(200)
    return cooldown(config.spell) == 0 and SKIP or SUCCESS
    end
    end
    elseif config.type == SINGLE_TARGET_RUNE then
    return function()
    -- Skip if we dont have a target or we dont have the rune
    if itemcount(config.spell) == 0 then return SKIP end
    -- Retry if the spell is on cooldown
    if cooldown("exori flam") > 0 then return SKIP end

    local function wouldDieToAStrike(c)
    local distance = math.max(math.abs($posx - c.posx), math.abs($posy - c.posy))
    if distance > 3 then return false end

    local info = creatureinfo(c.name)
    local hp = c.hppc * info.hp / 100
    local _, dmg = getBestStrike(c)
    return dmg >= hp
    end

    local rinfo = runeinfo(config.spell)
    local target, bdmg, bkills
    foreach creature c "mf" do
    if ((not config.monsters) or config.monsters[c.name:lower()]) and
    (not config.filter or config.filter(c)) and c.isshootable then
    if wouldDieToAStrike(c) then
    return SKIP
    end
    local info = creatureinfo(c.name)
    local hp = info.hp * c.hppc / 100
    local mod = info[rinfo.dmgtype:lower() .. "mod"] / 100
    local mindmg = mod * rinfo.mindmg
    local dmg = math.min(mindmg, hp)
    local kills = mindmg >= hp
    if (not target) or
    (kills and not bkills) or
    (dmg > bdmg)
    then
    target = c
    bdmg = dmg
    bkills = kills
    end
    end
    end
    -- Check that the target is valid for out spell before casting
    local c = $target
    if target then
    -- Retry if the spell is still on a short cooldown
    useoncreature(config.spell, target)
    if cooldown("exori flam") ~= 0 then
    lastRuneCast = os.clock()
    return SUCCESS
    else
    return SKIP
    end
    else
    return SKIP
    end
    end
    end
    end

    function parseConfig(ShooterConfig)
    local spells = {}

    -- The blacklist is a list of IDs. If an ID from the blacklist is on the screen
    -- the shooter will enable multi-floor pvp safety.
    local blacklist = {}
    for _, id in ipairs(ShooterConfig.blacklistIds) do
    blacklist[id] = true
    end

    -- The set of ball targets is used to allow the potion drinker to drink more frequently.
    local ballTargets = {}

    for _, spell in ipairs(ShooterConfig.spells) do
    local config = convertSpellConfig(spell)

    local shooter = getShooterFunc(config, blacklist)
    table.insert(spells, {name = config.spell, type = config.type, shooter = shooter})

    if config.type == BALL then
    if config.monsters and ballTargets then
    for _, name in ipairs(config.monsters) do
    ballTargets[name] = true
    end
    else
    ballTargets = nil
    end
    end
    end

    return {spells, blacklist}, ballTargets
    end

    function getBestStrike(target)
    local targetName = target.Name
    local info = creatureinfo(targetName)
    local hp = target.hppc * info.hp / 100
    local spells = {"exori flam", "exori frigo", "exori vis", "exori tera"}
    if $vocshort == "S" then
    table.insert(spells, "exori mort")
    if Config.useStrongStrikes then
    table.insert(spells, "exori gran vis")
    table.insert(spells, "exori gran flam")
    end
    elseif $vocshort == "D" then
    table.insert(spells, "exori moe ico")
    if Config.useStrongStrikes then
    table.insert(spells, "exori gran frigo")
    table.insert(spells, "exori gran tera")
    end
    end

    local function priority(spell)
    local sinfo = spellinfo(spell)
    local mod = info[sinfo.dmgtype:lower() .. "mod"] / 100
    if mod * sinfo.mindmg > hp then
    return hp, sinfo.mp, mod
    else
    return mod * sinfo.mindmg, sinfo.mp, mod
    end
    end

    local bspell, bdmg, bmp, bmod
    for _, spell in ipairs(spells) do
    local sdmg, smp, smod = priority(spell)
    local hotkeyed = clientspellhotkey(spell) ~= 'not found' or $fasthotkeys
    if cooldown(spell) == 0 and hotkeyed and (not bspell or sdmg > bdmg or (sdmg == bdmg and smp < bmp) or (sdmg == bdmg and smp == bmp and smod > bmod)) then
    bspell, bdmg, bmp, bmod = spell, sdmg, smp, smod
    end
    end

    return bspell, bdmg
    end

    local function tryCastBestStrike(players)
    local c = $target

    -- Don't case without a target!
    if c.id == 0 then return SKIP end

    local spell = getBestStrike(c)
    -- getBestSpell only returns nil if all strikes are on cooldown
    if not spell then return SKIP end

    -- Skip if we dont have mana
    if $mp < spellinfo(spell).mp then return SKIP end

    local lx, ly = getLookPos()
    local score = getScore(posToNum(lx, ly), currentMasks["exori flam"][$self.dir], nil, players, nil, Config.pvpsafe)
    -- If the strike isn't pvpsafe, then try turning away from any other player and then skip the spell.
    -- Don't retry since that may get us stuck in a loop.
    if score == -1 then
    tryTurnAway()
    return SKIP
    end

    -- Check that the target is in range before casting
    if math.max(math.abs(c.posx - $posx), math.abs(c.posy - $posy)) <= 3 and $target.id ~= 0 then
    cast(spell)
    return cooldown(spell) == 0 and RETRY or SUCCESS
    end
    return SKIP
    end

    local function tryCastSpell(spells, blacklist)
    local monsters, players, shootables = getSurroundings(Config.multiFloor, blacklist)
    for _, spell in ipairs(spells) do
    status = spell.shooter(currentMasks[spell.name], monsters, players, shootables)
    if status == SUCCESS or status == RETRY then
    return
    end
    monsters, players, shootables = getSurroundings(Config.multiFloor, blacklist)
    end
    tryCastBestStrike(players)

    end

    pconfig, _RuneMonsters = parseConfig(Config)
    local pconfig = pconfig

    lastRuneCast = 0
    lastDrunk = 0

    updateMasks()
    init end

    -- Check for players to disable ue
    foreach creature c 'pf' do
    local isPartyMember = c.party >= 3 and c.party <= 10
    if c.name ~= $name and not (Config.ignoreParty and isPartyMember) then
    lastPlayerSeenTime = os.clock()
    end
    end

    -- Cast a spell
    if not $pzone then
    tryCastSpell(unpack(pconfig))
    end

    -- Drink a potion
    local timeToNextCast = cooldown(SPELL_GROUP_ATTACK)
    local timeSinceRuneCast = os.clock() - lastRuneCast
    local potion = Config.manaPotion
    local precount = itemcount(potion)

    if precount > 0 then
    if (timeSinceRuneCast > 1 and os.clock() - lastDrunk > 1) and
    ($mppc < 30 or ($mppc < 80 and (maround(7, unpack(_RuneMonsters)) < 2 or timeToNextCast > 800))) then
    useoncreature(potion, $self)
    if precount ~= itemcount(potion) then
    lastDrunk = os.clock()
    end
    end
    end


    auto(100)

 

 

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •