XenoBot Forums - Powered by vBulletin

User Tag List

Page 1 of 5 123 ... LastLast
Results 1 to 10 of 46

Thread: [Update] XenoBot Apophis v14.11.19.995 [Team Scripts | Protocol 10.82]

  1. #1
    XenoBot Developer DarkstaR's Avatar
    Join Date
    Dec 2010
    Posts
    6,104
    Mentioned
    1326 Post(s)
    Tagged
    16 Thread(s)

    [Update] XenoBot Apophis v14.11.19.995 [Team Scripts | Protocol 10.82]

    Keeping with the trend of the last few updates, this is a huge update. Other than the obvious 10.82 compatibility, this update features some improvements: utito tempo will work with recovery, targeting now has many more options for priorities, and the Walker will now automatically detect the rope or shovel of the user. To round out these improvements, I've also added some new features that allow Scripters to easily make team scripts. This update will be automatically installed when you restart XenoSuite.

    Changelog:
    Code:
    v14.11.19.995
    Added 10.82 compatibility.
    Fixed a bug that caused Empowerments in the Scripter to not work with Recovery spells.
    Re-coded the spell timer system and HUD to be more specific and versatile.
    Improved Targeting to have ten priority options instead of five.
        Lowest, Very Low, Low, Medium Low, Medium, Medium High, High, Very High, Super High, Highest
        The old priorities will slot into Lowest - Medium, and all relevant settings should stay the same relative to
        these, so old scripts should work flawlessly still.
    Improved the Walker to automatically detect rope and shovel in open backpacks.
        If there are no tools visible, the Walker will obey the tools selected in the Walker Options panel like before.
    Added GenericTextMessageProxy class to the Scripter.
        Functionality:
            This works just like all of the other text message proxies.
            It will catch all messages that don't have a specific proxy (raid messages, player is far to the south, etc).
    Added Self.WalkTo to the Scripter.
        Functionality:
            Tries to walk to the position.
        Parameters:
            x: x coordinate in the map on the x-axis
            y: y coordinate in the map on the y-axis
            z: z coordinate in the map on the z-axis
        Return:
            True if the position is reached, false its:
                1. Not reachable for 2 consecutive seconds
                2. On a different floor
    Added IpcPublisherSocket to the Scripter.
    Added IpcSubscriberSocket to the Scripter.
    Added IpcResponderSocket to the Scripter.
    Added IpcRequestorSocket to the Scripter.
        The four classes above are part of XenoBot's new IPC (inter-process communication) layer.
        The purpose of this new layer is to allow Lua scripts running on MULTIPLE CHARACTERS to talk to each-other.
        See below for details on how to use these classes.
    Simple examples
    Badass example

  2. #2
    XenoBot Developer DarkstaR's Avatar
    Join Date
    Dec 2010
    Posts
    6,104
    Mentioned
    1326 Post(s)
    Tagged
    16 Thread(s)
    Self.WalkTo()

    This one is pretty simple.

    lua code:


    if not Self.WalkTo(x, y, z) then
    print("failed to walk to destination")
    else
    print("arrived at destination")
    end




    GenericTextMessageProxy

    This one is also pretty simple.

    lua code:


    local proxy = GenericTextMessageProxy.New("my-proxy")


    proxy:OnReceive(function (proxy, message)
    print("Got message: %s", message)
    end)




    New IPC Classes

    The new IPC feature in XenoBot uses sockets to allow multiple bots to communicate. Unlike traditional sockets, these sockets are stateless. The server can be started before or after the clients and the server can be reset at will, and the underlying framework will automatically manage reconnecting for you. Like traditional sockets, though, each unique set of sockets will need a unique port on which they communicate. Additionally, for this initial release, only bots on the same machine can communicate. There are four different types of sockets, and an equal number of classes: IpcPublisherSocket, IpcSubscriberSocket, IpcResponderSocket, and IpcRequestorSocket. These four socket types actually make up two different communication patterns: PUB/SUB and REP/REQ.

    PUB/SUB

    The PUB/SUB pattern is a pattern in where there is one script acting as a publisher, and many scripts acting as subscribers. A publisher can publish messages to all of its subscribers, and each message can be filtered by a topic, so that only subscribers listening to that topic will hear it. Here's an example, albeit a bit contrived.

    This is the publisher socket. It should be run on one client, and one client only.

    lua code:


    local publisher = IpcPublisherSocket.New("test-ipc-pub-socket", 30123)


    local count = 0
    while (true) do
    publisher:PublishMessage("Topic 1", "this is message #" .. count .. " on topic 1")
    count = count + 1
    wait(5000)
    end



    This is the subscriber socket. It can be run on any number of clients, and it will receive the messages broadcasted by the publisher.

    lua code:


    local subscriber = IpcSubscriberSocket.New("test-ipc-sub-socket", 30123)


    subscriber:AddTopic("Topic 1")


    while (true) do
    local hasMessage, topic, data = subscriber:Recv()
    while (hasMessage) do
    print("[%s]: %s", topic, data)
    hasMessage, topic, data = subscriber:Recv()
    end
    wait(200)
    end



    Notice that these sockets are using port 30123 to communicate.

    REP/REQ

    The REP/REQ pattern is one where there's one script acting as a responder, and many scripts acting as requestors. A responder can receive single messages from each of it's requestors, and must reply with a response before doing anything else. In turn, each requestor must wait for a response before sending another request. Think of it like a question and answer session. Here's an example where the requestors come up with math questions, and the responder answers them.

    This is the responder socket, it must only be run on one client.

    lua code:


    local responder = IpcResponderSocket.New("test-ipc-rep-socket", 30321)


    local count = 0
    while (true) do
    local success, request = responder:GetRequest()
    while (success) do
    local resonse = loadstring("return (" .. request .. ")")()
    responder:SendResponse(resonse)
    success, request = responder:GetRequest()
    end
    wait(200)
    end



    This is the requestor socket, it can run on as many clients as you wish:

    lua code:


    local requestor = IpcRequestorSocket.New("test-ipc-req-socket", 30321)


    local count = 0
    while (true) do
    local mathRequest = math.random(5, 90) .. " + " .. math.random(5, 50) .. " - " .. math.random(1, 50) .. " * " .. math.random(2, 4)
    requestor:SendRequest(mathRequest)
    print("Got the answer '%s' to question '%s'", requestor:GetResponse(), mathRequest)
    wait(10000)
    end



    Notice that these sockets are using port 30321 to communicate.

    Don't try to mix any of these sockets in ways not mentioned here. For instance, don't do REP/SUB, PUB/REQ, SUB/REQ, etc. This is undefined and unintended behavior, and has the potential to lead to crashes or deadlocks.

  3. #3
    XenoBot Developer DarkstaR's Avatar
    Join Date
    Dec 2010
    Posts
    6,104
    Mentioned
    1326 Post(s)
    Tagged
    16 Thread(s)
    A Practical Example of IPC

    Since the last examples were a bit simple, I wanted to go ahead and make a script that used IPC in a cool way. Well, not to toot my own horn, but I fucking delivered; and i'm open sourcing it. This script is far from perfect, but its a good start, and I took care of all the complex math already.

    The purpose of this script is to run up to 20 drones around the map that will mimic the exiva's casted by the main player, and communicate that data back to said player. All of the results will display on a HUD, showing things like "very far to the east of thais" or "far south of venore". If any of the drones encounter the target player (readas: if he's close by, next to the drone, or above/below the drone), the script will say something like this in the server log:

    The target player is near "My Exiva Dude 3" in "Thais".
    If the target player is far or very far from all of the drones, though, some magic takes place. The script will use some moderately advanced trigonometry to triangulate the position of the player, based on the areas from each exiva. It does this by calculating a region that the target player MUST be inside of. From there, it looks at a list of known towns and hunting spots (thanks to @Rydan, @Fatality, and @kimse for helping me with these lists) in that region, and tells you the top six locations where the player might be. If there's no known locations inside of the area, it will tell you the center xy position and the outline of the polygon, so you can take a look at the data on tibia.xyz or another mapping site. If all else fails, you will still have a large list of exiva results to help locate the player on your own.

    Before I jump in to the actual code, I'd like to note that me and @kimse have determined the optimal locations for each drone without the need for PACC: Thais Bless, Folda Boat, Carlin Temple, Kaz North, Ab Boat, Demon Oak Reward, and Venore Boat. If you exiva from either Darashia Carpet or Darashia Boat on the main character, this will cover the entire map very well.




    With further talking, here's the code.


    exiva_server.lua, this goes on the main character


    lua code:



    dofile("exiva_common.lua")


    -- variables for triangulation
    local triangulated = false
    local lastExivaMessageTime = 0
    local exivaData = {}
    local latestMessages = {}


    -- create title HUD
    local HUDTitle = HUD.CreateTextDisplay(CONFIG.HUDLocation.x, CONFIG.HUDLocation.y, "", unpack(CONFIG.HUDColors.title))


    -- create HUD lines for each exiva result
    local HUDsDisplayed = 0
    local HUDData = {}
    for index = 1, 20 do
    HUDData[index] = HUD.CreateTextDisplay(
    CONFIG.HUDLocation.x + 5,
    -- +12 pixels to the y axis for every item
    CONFIG.HUDLocation.y + ((index - 1) * 12) + 12,
    "",
    -- text color
    unpack(CONFIG.HUDColors.message)
    )
    end


    -- create two server sockets to communicate with clients
    local pubsock = IpcPublisherSocket.New("pub-socket", CONFIG.IPCPorts.pubsub)
    local repsock = IpcResponderSocket.New("rep-socket", CONFIG.IPCPorts.repreq)




    -- detect exiva casts
    LocalSpeechProxy.New("speech-proxy"):OnReceive(function(proxy, type, speaker, level, message)
    if (speaker == Self.Name() and string.starts(message, "exiva")) then
    -- get the name of the exiva target
    local targetPlayer = string.sub(message, 8)
    targetPlayer = string.sub(targetPlayer, 1, string.len(targetPlayer) - 1)


    -- reset all of the HUD stuff for the last exiva target
    HUDTitle:SetText(CONFIG.HUDTitle .. targetPlayer)
    HUDsDisplayed = 0
    for _, HUDLine in pairs(HUDData) do
    HUDLine:SetText("")
    end


    -- reset all of the triangulation stuff
    triangulated = false
    exivaData = {}
    lastExivaMessageTime = 0


    -- find the result of this exiva (comes before the speech does) and store it
    for i = #latestMessages, 1, -1 do
    if (string.starts(latestMessages[i], targetPlayer)) then
    local locationString, townName = parseExivaMessage(latestMessages[i], targetPlayer)
    local message = createIpcMessage(locationString, townName)
    handleExivaResult(message)
    break
    end
    end
    latestMessages = {}


    -- publish the target name to the clients
    pubsock:PublishMessage("target", targetPlayer)
    end
    end)




    -- catch all generic messages and store them to use later
    GenericTextMessageProxy.New("generic-proxy"):OnReceive(function (proxy, message)
    latestMessages[#latestMessages+1] = message
    end)




    -- Handle incoming exiva results from clients and triangulate after they're all received
    Module.New('rep-listen', function()
    local success, request = repsock:GetRequest()
    while (success) do
    -- tell the req socket we've got the message
    repsock:SendResponse("ack")
    -- handle it
    handleExivaResult(request)
    -- check for new messages
    success, request = repsock:GetRequest()
    end


    if (not triangulated and lastExivaMessageTime ~= 0 and os.clock() - lastExivaMessageTime > 1.5) then
    triangulated = true
    triangulate()
    end
    end)


    function handleExivaResult(result)
    --parse the message
    local parts = string.split(result, "|")
    local showMessage = parts[1] .. " of " .. parts[4]


    -- update the hud
    HUDsDisplayed = HUDsDisplayed + 1
    HUDData[HUDsDisplayed]:SetText(showMessage)


    -- store this for use with triangulator
    exivaData[HUDsDisplayed] = {message = parts[1], x = tonumber(parts[2]), y = tonumber(parts[3]), town = parts[4], drone = parts[5]}
    lastExivaMessageTime = os.clock()
    end


    -- triginometry code to overlap exiva regions


    ANGLES =
    {
    SOUTH_EAST = 7426.0,
    EAST = 6977.0,
    NORTH_EAST = 6528.0,
    NORTH = 6079.0,
    NORTH_WEST = 5627.0,
    WEST = 5171.0,
    SOUTH_WEST = 4722.0,
    SOUTH = 4273.0,
    SWEEP = 449.0
    }


    ANGLE_MAPPING =
    {
    {"south-east", ANGLES.SOUTH_EAST},
    {"north-east", ANGLES.NORTH_EAST},
    {"north-west", ANGLES.NORTH_WEST},
    {"south-west", ANGLES.SOUTH_WEST},
    {"east", ANGLES.EAST},
    {"north", ANGLES.NORTH},
    {"west", ANGLES.WEST},
    {"south", ANGLES.SOUTH},
    }


    function createPoint(x, y, radius, angle)
    local nx = x + math.cos(angle * 0.01745) * radius
    local ny = y + math.sin(angle * 0.01745) * radius
    return {x = nx, y = ny}
    end


    function exivaMessageToPolygon(message, x, y)
    local radiusLow = 0
    local radiusHigh = 0
    local angleStart = 0
    local angleEnd = 0
    local angleMiddle = 0


    if (string.find(message, "very far")) then
    radiusLow = 276
    radiusHigh = 4000
    elseif (string.find(message, "far")) then
    radiusLow = 101
    radiusHigh = 275
    else
    return true, {}
    end


    for _, angle in pairs(ANGLE_MAPPING) do
    if (string.find(message, angle[1], 1, true)) then
    angleStart = angle[2] / 10.0
    angleEnd = (angle[2] / 10.0) + (ANGLES.SWEEP / 10.0)
    angleMiddle = (angle[2] / 10.0) + (ANGLES.SWEEP / 20.0)
    break
    else
    end
    end


    -- polygon is a sort of pointy cone, and has 6 points (example of an exiva to the north):
    --[[
    _3_
    2__--- ---__4
    \ /
    \ 6 /
    \__- -__/
    1 5
    --]]
    local poly =
    {
    createPoint(x, y, radiusLow, angleStart),
    createPoint(x, y, radiusHigh, angleStart),
    createPoint(x, y, radiusHigh, angleMiddle),
    createPoint(x, y, radiusHigh, angleEnd),
    createPoint(x, y, radiusLow, angleEnd),
    createPoint(x, y, radiusLow, angleMiddle),
    }
    return false, poly
    end


    function triangulate()
    -- generate the polygons for each exiva cast
    local polygons = {}
    for i, data in ipairs(exivaData) do
    local found, polygon = exivaMessageToPolygon(data.message, data.x, data.y)
    if (found) then
    if (data.self) then
    print("Target player is very close to you")
    else
    print("Target player is very close to '%s' in '%s'", data.drone, data.town)
    end
    return nil
    end


    polygons[i] = polygon
    end


    -- clip the polygons againmst eachother to come up with the overlapping area
    -- and also against the Tibia map to get rid of excess areas
    local clipped = clip(polygons[1], TIBIA_MAP_POLYGON)
    for i = 2, #polygons do
    clipped = clip(clipped, polygons[i])
    end


    -- find the center of the final polygon
    local center = centroid(clipped)
    local locations = {}
    for name, pos in pairs(HUNTING_SPOTS) do
    local point = {x = pos[1], y = pos[2]}
    if (pointinpoly(point, clipped)) then
    locations[#locations+1] = {name = name, dist = distance(point, center)}
    end
    end


    table.sort(locations, function(a,b) return a.dist<b.dist end)


    if (#locations > 6) then
    for i = 6, #locations do
    locations[i] = nil
    end
    end


    --print("Center: %s", table.serialize(center))
    --print("Polygon: %s", table.serialize(clipped))
    --print("Locations: %s", table.serialize(locations))


    for i, place in pairs(locations) do
    print("Target player might be in '%s' (this location is %d SQM from the center of the estimated region)", place.name, place.dist)
    end


    if (#locations == 0) then
    print("No location found.")
    print("Center: %s", table.serialize(center))
    print("Polygon: %s", table.serialize(clipped))
    end
    end




    -- polygon specific triginometry
    function distance(point1, point2)
    return math.sqrt(math.pow(math.abs(point1.x - point2.x), 2) + math.pow(math.abs(point1.y - point2.y), 2))
    end


    function pointinpoly(point, polygon)
    local hit = false
    local j = #polygon
    for i, vertex in ipairs(polygon) do
    if ( ((polygon[i].y > point.y) ~= (polygon[j].y > point.y)) and
    (point.x < (polygon[j].x - polygon[i].x) * (point.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x) ) then
    hit = not hit
    end
    j = i
    end
    return hit
    end


    function centroid(polygon)
    local minx = 65535
    local maxx = 0
    local miny = 65535
    local maxy = 0
    for i, vertex in ipairs(polygon) do
    minx = math.min(minx, vertex.x)
    maxx = math.max(maxx, vertex.x)
    miny = math.min(miny, vertex.y)
    maxy = math.max(maxy, vertex.y)
    end


    return {x = minx + (maxx - minx) / 2.0, y = miny + (maxy - miny) / 2.0}
    end


    function inside(p, cp1, cp2)
    return (cp2.x - cp1.x) * (p.y-cp1.y) > (cp2.y - cp1.y) * (p.x - cp1.x)
    end

    function intersection(cp1, cp2, s, e)
    local dcx, dcy = cp1.x - cp2.x, cp1.y - cp2.y
    local dpx, dpy = s.x - e.x, s.y - e.y
    local n1 = cp1.x * cp2.y - cp1.y * cp2.x
    local n2 = s.x * e.y - s.y * e.x
    local n3 = 1 / (dcx * dpy - dcy * dpx)
    local x = (n1 * dpx - n2 * dcx) * n3
    local y = (n1 * dpy - n2 * dcy) * n3
    return {x = x, y = y}
    end

    function clip(subjectPolygon, clipPolygon)
    local outputList = subjectPolygon
    local cp1 = clipPolygon[#clipPolygon]
    for _, cp2 in ipairs(clipPolygon) do -- WP clipEdge is cp1,cp2 here
    local inputList = outputList
    outputList = {}
    local s = inputList[#inputList]
    for _, e in ipairs(inputList) do
    if inside(e, cp1, cp2) then
    if not inside(s, cp1, cp2) then
    outputList[#outputList+1] = intersection(cp1, cp2, s, e)
    end
    outputList[#outputList+1] = e
    elseif inside(s, cp1, cp2) then
    outputList[#outputList+1] = intersection(cp1, cp2, s, e)
    end
    s = e
    end
    cp1 = cp2
    end
    return outputList
    end





    exiva_client.lua, this gets execute by each of the drone characters


    lua code:



    dofile("exiva_common.lua")


    -- vars
    local currentTargetName = "---------------------------------"


    -- create two client sockets to communicate with server
    local subsock = IpcSubscriberSocket.New("sub-socket", CONFIG.IPCPorts.pubsub)
    local reqsock = IpcRequestorSocket.New("req-sock", CONFIG.IPCPorts.repreq)
    subsock:AddTopic("target")


    -- detect exiva results
    GenericTextMessageProxy.New("generic-proxy"):OnReceive(function (proxy, message)
    if (string.starts(message, currentTargetName)) then
    -- parse the message and find the closest town
    local locationString, townName = parseExivaMessage(message, currentTargetName)
    -- send results to the server
    local message = createIpcMessage(locationString, townName)
    reqsock:SendRequest(message)
    reqsock:GetResponse()
    end
    end)


    -- Handle incoming exiva requests from server
    Module.New('sub-listen', function()
    local hasMessage, topic, data = subsock:Recv()
    while (hasMessage) do
    currentTargetName = data
    Self.Say("exiva \"" .. currentTargetName)
    hasMessage, topic, data = subsock:Recv()
    end
    end)







    exiva_common.lua, don't run this on any chars, it's just a library

    lua code:



    --[[ CONFIG START ]] --


    CONFIG =
    {
    HUDTitle = "Exiva On ",
    HUDLocation = { x = 25, y = 5 },
    HUDColors =
    {
    message = {95, 247, 247},
    title = {225, 225, 225},
    },
    IPCPorts =
    {
    pubsub = 30269,
    repreq = 30268,
    }
    }




    --[[ UTILS START ]] --
    TIBIA_MAP_POLYGON =
    {
    {x = 31904, y = 31004},
    {x = 33750, y = 31004},
    {x = 33750, y = 33020},
    {x = 31904, y = 33020},
    }


    HUNTING_SPOTS =
    {
    ["Tarpit Tomb"] = {33232, 32704, 7},
    ["Peninsula Tomb"] = {33025, 32868, 7},
    ["Hydra Mountain (North)"] = {32979,32627,7},
    ["Hydra Mountain (South)"] = {32988,32683,7},
    ["New Ancient Scarabs"] = {33359, 32657, 12},
    ["GS Tomb"] = {33047, 32571, 11},
    ["Shadow Tomb"] = {33245, 32853, 13},
    ["Ancient Ruins Tomb"] = {33290, 32557 , 13},
    ["Lion's Rock"] = {33146, 32338, 7},
    ["Darashia Dragons"] = {33265, 32277, 7},
    ["Darashia Minotaurs"] = {33308, 32285, 7},
    ["Darashia North East Wasps"] = {33307, 32341, 7},
    ["Darashia City wasps"] = {33210, 32384, 7},
    ["Drefia Wyrms"] = {33089, 32394, 13},
    ["Drefia Grims"] = {33044, 32457, 13},
    ["Ape City Surface"] = {32812, 32547, 7},
    ["Banuta Main Floor"] = {32822, 32577, 11},
    ["Medusa Tower"] = {32867, 32831, 7},
    ["Old Water Elementals"] = {32532, 32821, 7},
    ["Forbidden Lands Hydras"] = {32976, 32549, 7},
    ["Banuta -1"] = {32785, 32583, 12},
    ["Banuta -2"] = {32782, 32572, 13},
    ["Banuta -3"] = {32771, 32609, 14},
    ["Banuta -4"] = {32801, 32626, 15},
    ["Asura Palace"] = {32947, 32681, 7},
    ["New Water Elementals"] = {32644, 32995, 8},
    ["Orc Fortress"] = {32916, 31776, 7},
    ["Dark Cathedral"] = {32662, 32346, 7},
    ["Venore Coryms"] = {33051, 32120, 11},
    ["Venore Dragons"] = {32807,32157,7},
    ["Plains of Havoc Temple"] = {32816,32272,7},
    ["Plains of Havoc Center"] = {32728,32276,7},
    ["Outlaw Camp"] = {32663,32346,7},
    ["Outside Orc Fortress - West"] = {32800,31790,7},
    ["Outside Orc Fortress - North"] = {32927,31710,7},
    ["PoI DLs"] = {32789, 32334, 12},
    ["PoI DT Seal"] = {32778, 32237, 15},
    ["PoI Hellhound Seal"] = {32880, 32229, 15},
    ["PoI Juggernaut Seal"] = {32872, 32279, 15},
    ["PoI Undead Dragon Seal"] = {32833, 32278, 15},
    ["PoI Plauge Seal"] = {32843, 32349, 15},
    ["Cyclops Mountain"] = {32458, 32073, 7},
    ["Greenshore"] = {32260, 32074, 7},
    ["Mintwallin"] = {32414, 32132, 15},
    ["Fibula"] = {32175,32409,7},
    ["Thais Blessing temple"] = {32345,32365,7},
    ["Thais South Cyclops"] = {32417,32387,7},
    ["Fibula"] = {32168, 32379, 9},
    ["Cyclopolis"] = {33242, 31681, 9},
    ["Hero Fortress"] = {33323, 31580, 10},
    ["Edron Bog Raiders"] = {33345, 31761, 13},
    ["Edron Trolls"] = {33118, 31778, 7},
    ["Edron Goblins"] = {33120, 31832, 7},
    ["Edron Behemoths"] = {33301, 31698, 15},
    ["Inq Spectres"] = {33111, 31775, 13},
    ["Inq HFFs"] = {33164, 31712, 13},
    ["Edron Demons"] = {33103, 31710, 15},
    ["Maze of Lost Souls"] = {32467, 31645, 11},
    ["Demona"] = {32479,31627,14},
    ["Ghost Lands"] = {32217,31819,7},
    ["Banshee Quest"] = {32233,31864,11},
    ["Femur Hills"] = {32564, 31806, 7},
    ["Liberty Bay Wyrms Mountain"] = {32417, 32761, 7},
    ["Quara Grotto"] = {32243, 32899, 8},
    ["Ramoa (BB Island)"] = {31932,32577,7},
    ["Goroma"] = {32130, 32560, 7},
    ["Goroma Serpent Spawns"] = {31928, 32631, 11},
    ["Talahu (Hydra Island)"] = {31958,32664,7},
    ["Malada (GS Island)"] = {32012,32718,7},
    ["Nargor Pirates"] = {31990, 32859, 6},
    ["Liberty Bay Wyrms Underground"] = {32419, 32847, 9},
    ["Oramond Boat"] = {33490, 31986, 7},
    ["Oramond Minotaurs South"] = {33597, 32028, 7},
    ["Oramond Minotaurs East"] = {33704, 31939, 7},
    ["Oramond Furies / Undead Drags"] = {33650, 31839, 7},
    ["Seacrest Serpents Entrance"] = {33545, 31860, 7},
    ["Oramond West"] = {33543, 31893, 7},
    ["Oramond Tower"] = {33550, 31929, 7},
    ["Oramond Hydras"] = {33486, 31924, 10},
    ["Southeast Oramond Minotaurs"] = {33628, 32053, 7},
    ["Oramond Catacombs"] = {33469, 31762, 8},
    ["Seacrest Serpents North"] = {33490, 31685, 15},
    ["Seacrest Serpents South"] = {33468, 31816, 15},
    ["Oramond Grims/Demons"] = {33469, 32056, 10},
    ["Roshamuul South of bridge"] = {33572, 32553, 7},
    ["Roshamuul Bridge"] = {33541, 32529, 6},
    ["Guzzlemaw Valley"] = {33626, 32483, 7},
    ["Roshamuul Prison"] = {33567, 32379, 10},
    ["Roshamuul Depot"] = {33547, 32380, 7},
    ["War Golems"] = {32904, 31288, 7},
    ["Mistrock Cyclops"] = {32591, 31437, 7},
    ["Yalahar Arena Quarter"] = {32676, 31230, 7},
    ["Yalahar Alchemist Quarter"] = {32692, 31133, 7},
    ["Hellspawns"] = {32859, 31046, 7},
    ["Yalahar Grim Reapers"] = {32774, 31060, 8},
    ["Vengoth"] = {32953, 31463, 7},
    ["Fenrock DLs"] = {32593, 31364, 15},
    ["Svargrond Barbarian Camp"] = {32021, 31406, 7},
    ["Svargrond Arena"] = {32192, 31081, 7},
    ["Nibelor"] = {32359, 31080, 7},
    ["Okolnir"] = {32233, 31417, 7},
    ["New Chosens"] = {33179, 31196, 7},
    ["Corruption Hole"] = {33298, 31145, 9},
    ["Lizard City"] = {33078, 31186, 7},
    ["Killer Caimans"] = {33101, 31447, 7},
    ["Souleaters"] = {33164, 31059, 7},
    ["Lizard Village"] = {33238, 31165, 7},
    ["Farmine Dragons"] = {33190, 31293, 7},
    ["Kazordoon Dwarf Mines"] = {32502,31919,8},
    ["Lower Spike"] = {32243, 32604, 8},
    ["Hive"] = {33532, 31252, 7},
    ["Warzone 1/2/3"] = {33036, 31933, 12},
    ["Deeplings"] = {33457, 31194, 12},
    }


    NPC_DATA =
    {
    {name = "Anderson", destinations = {["folda"] = {32046,31580,7}, ["tibia"] = {32234,31675,7}, ["vega"] = {32022,31692,7},}},
    {name = "Barry", destinations = {["magician"] = {32884,31156,7}, ["sunken"] = {32884,31164,7},}},
    {name = "Brodrosch", destinations = {["cormaya"] = {33309,31989,15}, ["farmine"] = {33024,31552,10},}},
    {name = "Bruce", destinations = {["alchemist"] = {32737,31113,7}, ["cemetery"] = {32745,31113,7},}},
    {name = "Buddel", destinations = {["barbarian camp"] = {32021,31294,7}, ["helheim"] = {32462,31174,7}, ["okolnir"] = {32224,31381,7}, ["svargrond"] = {32256,31197,7}, ["tyrsung"] = {32333,31227,7},}},
    {name = "Captain Bluebear", destinations = {["ab'dendriel"] = {32733,31668,6}, ["carlin"] = {32387,31821,6}, ["edron"] = {33193,31784,3}, ["liberty bay"] = {32283,32893,6}, ["oramond"] = {33479,31985,7}, ["port hope"] = {32530,32784,6}, ["roshamuul"] = {33493, 32568, 7}, ["svargrond"] = {32341,31108,6}, ["venore"] = {32954,32023,6}, ["yalahar"] = {32816,31272,6},}},
    {name = "Captain Breezelda", destinations = {["carlin"] = {32387,31821,6}, ["thais"] = {32312,32211,6}, ["venore"] = {32954,32023,6},}},
    {name = "Captain Chelop", destinations = {["thais"] = {32312,32211,6},}},
    {name = "Captain Cookie", destinations = {["liberty bay"] = {32298,32896,6},}},
    {name = "Captain Fearless", destinations = {["ab'dendriel"] = {32733,31668,6}, ["ankrahmun"] = {33091,32883,6}, ["carlin"] = {32387,31821,6}, ["darashia"] = {33289,32480,6}, ["edron"] = {33175,31764,6}, ["gray island"] = {33190, 31984, 7}, ["liberty bay"] = {32283,32893,6}, ["port hope"] = {32530,32784,6}, ["svargrond"] = {32341,31108,6}, ["thais"] = {32312,32211,6}, ["yalahar"] = {32816,31272,6},}},
    {name = "Captain Greyhound", destinations = {["ab'dendriel"] = {32733,31668,6}, ["edron"] = {33175,31764,6}, ["svargrond"] = {32341,31108,6}, ["thais"] = {32312,32211,6}, ["venore"] = {32954,32023,6}, ["yalahar"] = {32816,31272,6},}},
    {name = "Captain Gulliver", destinations = {["thais"] = {32312,32211,6},}},
    {name = "Captain Haba", destinations = {["hunt"] = {31942,31047,6}, ["svargrond"] = {32339,31117,7},}},
    {name = "Captain Jack", destinations = {["tibia"] = {32205,31756,6},}},
    {name = "Captain Max", destinations = {["calassa"] = {31920,32710,7}, ["liberty bay"] = {32298,32896,6}, ["yalahar"] = {32804,31270,6},}},
    {name = "Captain Seagull", destinations = {["carlin"] = {32387,31821,6}, ["edron"] = {33175,31764,6}, ["gray island"] = {33190, 31984, 7}, ["thais"] = {32312,32211,6}, ["venore"] = {32954,32023,6}, ["yalahar"] = {32816,31272,6},}},
    {name = "Captain Seahorse", destinations = {["ab'dendriel"] = {32733,31668,6}, ["ankrahmun"] = {33091,32883,6}, ["carlin"] = {32387,31821,6}, ["cormaya"] = {33288,31956,6}, ["gray island"] = {33190, 31984, 7}, ["liberty bay"] = {32283,32893,6}, ["port hope"] = {32530,32784,6}, ["thais"] = {32312,32211,6}, ["venore"] = {32954,32023,6},}},
    {name = "Captain Sinbeard", destinations = {["darashia"] = {33289,32480,6}, ["edron"] = {33175,31764,6}, ["liberty bay"] = {32283,32893,6}, ["port hope"] = {32530,32784,6}, ["venore"] = {32954,32023,6}, ["yalahar"] = {32816,31272,6},}},
    {name = "Captain Waverider", destinations = {["liberty bay"] = {32350,32856,7}, ["passage"] = {32132,32912,7}, ["peg leg"] = {32346,32625,7},}},
    {name = "Carlson", destinations = {["folda"] = {32046,31580,7}, ["senja"] = {32126,31665,7}, ["tibia"] = {32234,31675,7},}},
    {name = "Charles", destinations = {["ankrahmun"] = {33091,32883,6}, ["darashia"] = {33289,32480,6}, ["edron"] = {33175,31764,6}, ["liberty bay"] = {32283,32893,6}, ["thais"] = {32312,32211,6}, ["venore"] = {32954,32023,6}, ["yalahar"] = {32816,31272,6},}},
    {name = "Chemar", destinations = {["edron"] = {33193,31784,3}, ["farmine"] = {32983,31539,1}, ["femor hills"] = {32535,31837,4}, ["kazordoon"] = {32588, 31942, 0}, ["svargrond"] = {32254,31097,4},}},
    {name = "Dalbrect", destinations = {["passage"] = {32190,31957,6},}},
    {name = "Eremo", destinations = {["cormaya"] = {33288,31956,6},}},
    {name = "Gewen", destinations = {["darashia"] = {33269,32441,6}, ["edron"] = {33193,31784,3}, ["farmine"] = {32983,31539,1}, ["femor hills"] = {32535,31837,4}, ["svargrond"] = {32254,31097,4},}},
    {name = "Gurbasch", destinations = {["farmine"] = {33024,31552,10}, ["kazordoon"] = {32658, 31957, 15},}},
    {name = "Hal", destinations = {["alchemist"] = {32688,31187,7}, ["arena"] = {32688,31195,7},}},
    {name = "Harlow", destinations = {["vengoth"] = {32857,31549,7}, ["yalahar"] = {32837,31364,7},}},
    {name = "Imbul", destinations = {["banuta"] = {32826, 32631, 7}, ["center"] = {32628,32771,7}, ["chor"] = {32968,32799,7}, ["east"] = {32679,32777,7}, ["mountain hideout"] = {32987, 32730, 7},}},
    {name = "Iyad", destinations = {["darashia"] = {33269,32441,6}, ["edron"] = {33193,31784,3}, ["farmine"] = {32983,31539,1}, ["femor hills"] = {32535,31837,4}, ["kazordoon"] = {32588, 31942, 0},}},
    {name = "Jack Fate", destinations = {["ankrahmun"] = {33091,32883,6}, ["darashia"] = {33289,32480,6}, ["edron"] = {33175,31764,6}, ["goroma"] = {32161,32558,6}, ["liberty bay"] = {32283,32893,6}, ["port hope"] = {32530,32784,6}, ["thais"] = {32312,32211,6}, ["venore"] = {32954,32023,6}, ["yalahar"] = {32816,31272,6},}},
    {name = "Karith", destinations = {["ab'dendriel"] = {32733,31668,6}, ["ankrahmun"] = {33091,32883,6}, ["carlin"] = {32387,31821,6}, ["darashia"] = {33289,32480,6}, ["liberty bay"] = {32283,32893,6}, ["port hope"] = {32530,32784,6}, ["thais"] = {32312,32211,6}, ["venore"] = {32954,32023,6},}},
    {name = "Lorek", destinations = {["banuta"] = {32826, 32631, 7}, ["center"] = {32628,32771,7}, ["chor"] = {32968,32799,7}, ["mountain hideout"] = {32987, 32730, 7}, ["west"] = {32558,32780,7},}},
    {name = "Maris", destinations = {["fenrock"] = {32564,31313,7}, ["mistrock"] = {32640,31439,7}, ["yalahar"] = {32649,31292,6},}},
    {name = "Melian", destinations = {["darashia"] = {33269,32441,6}, ["edron"] = {33193,31784,3}, ["femor hills"] = {32535,31837,4}, ["kazordoon"] = {32588, 31942, 0}, ["svargrond"] = {32254,31097,4},}},
    {name = "Nielson", destinations = {["folda"] = {32046,31580,7}, ["senja"] = {32126,31665,7}, ["vega"] = {32022,31692,7},}},
    {name = "Old Adall", destinations = {["banuta"] = {32826, 32631, 7}, ["chor"] = {32968,32799,7}, ["east"] = {32679,32777,7}, ["mountain hideout"] = {32987, 32730, 7}, ["west"] = {32558,32780,7},}},
    {name = "Oliver", destinations = {["factory"] = {32895,31233,7}, ["sunken"] = {32895,31225,7},}},
    {name = "Pemaret", destinations = {["edron"] = {33175,31764,6}, ["eremo's island"] = {33315,31882,7},}},
    {name = "Peter", destinations = {["factory"] = {32860,31302,7}, ["trade"] = {32853,31302,7},}},
    {name = "Petros", destinations = {["ankrahmun"] = {33091,32883,6}, ["gray island"] = {33190, 31984, 7}, ["liberty bay"] = {32283,32893,6}, ["port hope"] = {32530,32784,6}, ["venore"] = {32954,32023,6}, ["yalahar"] = {32816,31272,6},}},
    {name = "Pino", destinations = {["darashia"] = {33269,32441,6}, ["farmine"] = {32983,31539,1}, ["femor hills"] = {32535,31837,4}, ["kazordoon"] = {32588, 31942, 0}, ["svargrond"] = {32254,31097,4},}},
    {name = "Rapanaio", destinations = {["isle of evil"] = {32667,31452,7}, ["kazordoon"] = {32700,31989,15},}},
    {name = "Reed", destinations = {["cemetery"] = {32798,31103,7}, ["magician"] = {32806,31103,7},}},
    {name = "Scrutinon", destinations = {["ab'dendriel"] = {32733,31668,6}, ["darashia"] = {33289,32480,6}, ["venore"] = {32954,32023,6},}},
    {name = "Sebastian", destinations = {["liberty bay"] = {32316,32702,7}, ["meriana"] = {32346,32625,7}, ["nargor"] = {32025,32812,7},}},
    {name = "Svenson", destinations = {["senja"] = {32126,31665,7}, ["tibia"] = {32234,31675,7}, ["vega"] = {32022,31692,7},}},
    {name = "Tarak", destinations = {["monument tower"] = {32941,31182,7}, ["yalahar"] = {32916,31199,7},}},
    {name = "Thorgrin", destinations = {["cormaya"] = {33309,31989,15}, ["kazordoon"] = {33309,31989,15},}},
    {name = "Tony", destinations = {["arena"] = {32695,31253,7}, ["foreign"] = {32695,31260,7},}},
    {name = "Uzon", destinations = {["darashia"] = {33269,32441,6}, ["edron"] = {33193,31784,3}, ["farmine"] = {32983,31539,1}, ["kazordoon"] = {32588, 31942, 0}, ["svargrond"] = {32254,31097,4},}},
    }


    -- make a list of town names and their locations
    local TownLocations = {["Demon Oak Rewards"] = {32710,32398,7}}
    for k, v in pairs(NPC_DATA) do
    for name, loc in pairs (v.destinations) do
    if (not string.find(name, "passage") and
    not string.find(name, "east") and
    not string.find(name, "tibia") and
    not string.find(name, "passage") and
    not string.find(name, "hunt") and
    not string.find(name, "center") and
    not string.find(name, "west")) then
    TownLocations[name] = loc
    HUNTING_SPOTS[name] = loc
    end
    end
    end


    -- internal funcs
    function createIpcMessage(locationString, townName)
    return locationString .. "|" .. Self.Position().x .. "|" .. Self.Position().y .. "|" .. townName .. "|" .. Self.Name()
    end


    function parseExivaMessage(message, currentTargetName)
    local distance = 65535
    local townName = ""
    for name, loc in pairs(TownLocations) do
    local checkDistance = Self.DistanceFromPosition(loc[1], loc[2], loc[3])
    if (checkDistance < distance) then
    townName = name
    distance = checkDistance
    end
    end


    -- get the location data from the message and merge it with the town
    local locationString = string.sub(message, string.len(currentTargetName) + 4)
    locationString = string.sub(locationString, 1, string.len(locationString) - 1)


    return locationString, townName
    end


    -- string helpers
    function string.starts(String,Start)
    return string.sub(String,1,string.len(Start))==Start
    end


    function string:split(sep)
    local sep, fields = sep or ":", {}
    local pattern = string.format("([^%s]+)", sep)
    self:gsub(pattern, function(c) fields[#fields+1] = c end)
    return fields
    end





  4. #4

    Join Date
    Jul 2015
    Posts
    5
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    when is this uppdate done`?

  5. #5
    Senior Member Jontor's Avatar
    Join Date
    Sep 2014
    Posts
    446
    Mentioned
    51 Post(s)
    Tagged
    1 Thread(s)
    Thanks for the update <3

  6. #6
    XenoBot Scripts Developer Joshwa534's Avatar
    Join Date
    May 2012
    Location
    Texas, USA
    Posts
    4,890
    Mentioned
    517 Post(s)
    Tagged
    3 Thread(s)


    Thank you sir!

  7. #7
    Moderator shadowart's Avatar
    Join Date
    Dec 2014
    Location
    Sweden
    Posts
    1,985
    Mentioned
    225 Post(s)
    Tagged
    3 Thread(s)
    It's liiiiiiiiiiiiiiiiiiive!! I see you also sneaked in a pair of throwaway calls to math.random that should fix the one-liner issues that @Ben had some time ago.

  8. #8
    Senior Member sausting's Avatar
    Join Date
    Aug 2012
    Location
    Ontario, Canada
    Posts
    1,018
    Mentioned
    39 Post(s)
    Tagged
    0 Thread(s)
    nice!

  9. #9
    XenoBot Developer DarkstaR's Avatar
    Join Date
    Dec 2010
    Posts
    6,104
    Mentioned
    1326 Post(s)
    Tagged
    16 Thread(s)
    Quote Originally Posted by shadowart View Post
    It's liiiiiiiiiiiiiiiiiiive!! I see you also sneaked in a pair of throwaway calls to math.random that should fix the one-liner issues that @Ben had some time ago.

    Those have been around for a few updates, actually

  10. #10
    Lifetime Subscriber
    Join Date
    Sep 2015
    Posts
    13
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Congratulations on the speed of update

Posting Permissions

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