• You've discovered RedGuides, an EverQuest multi-boxing and scripting community 🧙‍♀️⚙️. We want you to play several EQ characters at once, come join us and say hello! 👋

  • A TLP without truebox has thawed (Very Vanilla ready)
    Frostreaver

Lua - Lua Snips and discussion

So here is the way I do it, or did it.. this will determine if you have any component from any recipe for the GOD pottery freebie and if you have anything it will keep going, if you don't well.. WIN!

Code:
    local winning = 1
    for list_row in db:nrows(
                        "SELECT * FROM Legacy_Quest_Recipe_Table WHERE QuestSequence = 0 and QuestID=" ..
                            p_quest_id) do
        for list_row in db:nrows(
                            "SELECT * FROM MasterCompTable WHERE RecipeID=" ..
                                list_row.RecipeID) do
            if mq.TLO.FindItem(list_row.MItemID)() ~= nil then
                winning = 0
            end
        end
    end
    if winning == 1 then
        mq.cmd('/say recipes')
        mq.delay(1000)
        break
    end
 
You are doing doevents with no delay so if the event doesn’t occur right away it will wait 1s and the flush events

Even though I suck at doevents, in this case, it won't help anyhow. Because anyone can trigger the text, it is global, so no joy. The toon could exit based on what some other toon said.

That being said, I consider this a legacy quest. It doesn't appear in the task window ... the newer quests (whenever they did that) are easier to determine completion.

if there are events that only my toon sees, well I will revisit doevents for those.. :)
 
Last edited:
Grab plat from the bank...

Code:
function library.bank_withdrawal(p_amount)
    if not mq.TLO.Window.BigBankWnd.Open() then
        mq.cmd('/nomodkey /click right target')
        mq.delay(1500)
    end
    if mq.TLO.Me.PlatinumBank() >= p_amount then
        mq.cmd('/notify BigBankWnd BIGB_Money0 leftmouseup')
    else
        if mq.TLO.Me.PlatinumShared() >= p_amount then
            mq.cmd('/notify BigBankWnd BIGB_SharedMoney0 leftmouseup')
        else
            print("\ao[\atTCSNeXt\ao]: \ay[\awNot Enough Cash:\ay] \ap[\ag",
                  p_amount, "\ap] \atPlatinum \ay[\ayNeeded\ay]")
            return false
        end
    end
    print("\ao[\atTCSNeXt\ao]: \ay[\awGrabbing:\ay] \ap[\ag", p_amount,
          "\ap] \atPlatinum \agfrom: \ay[\ayBank\ay]")
    mq.delay(1000)
    mq.cmd('/notify QuantityWnd QTYW_slider newvalue ' .. p_amount)
    mq.delay(1000)
    mq.cmd('/notify QuantityWnd QTYW_Accept_Button leftmouseup')
    mq.delay(1000)
    mq.cmd('/autoinv')
    mq.delay(1000)
    mq.cmd('/notify BigBankWnd BIGB_DoneButton leftmouseup')
    mq.delay(1500)
    return false
end

This is good, change my mind.. Assumes you have targeted the banker...
 
Last edited:
modern bag/item management for portable container crafting:

The portable container wants to be in slot 32 or most bottom right. It will pick up anything that is of item type and drop it in any available slot and put the container in slot 32.
If there is a bag in slot 32 it will look for an empty slot and move the bag there and put the container in slot 32..

This is to mitigate crafting components in a lower slot than the container which is no bueno for portable container crafting.


Code:
if mq.TLO.Me.Inventory(32)() ~= craft_container then
        local item_type = {
            "Baking", "Medicine", "Fletching", "Jewelry Making", "Mixing",
            "Tinkering", "Make Poison", "Food", "Drink", "Misc", "Book",
            "Combinable", "Lexicon", "Alchemy", "Shield", "Armor", "nil"
        }
        local swappable = 0
        for x = 0, #item_type do
            if mq.TLO.Me.Inventory(32).Type() ~= item_type[x] then
                swappable = 1
                mq.delay(100)
            end
        end
        mq.delay(1500)
        if swappable == 1 then
            mq.cmd('/ctrl /itemnotify "' .. craft_container .. '" leftmouseup')
            mq.delay(1500)
            mq.cmd('/nomodkey /itemnotify 32 leftmouseup')
            mq.delay(1000)
            lib.ClearCursor()
        end
        lib.ClearCursor()
        mq.delay(1000)
        if swappable == 0 then
            local move_slot = 0
            for x = 23, 31 do
                if mq.TLO.Me.Inventory(x)() == nil then
                    move_slot = x
                end
            end
            if move_slot ~= 0 then
                mq.cmd('/nomodkey /itemnotify 32 leftmouseup')
                mq.delay(1000)
                mq.cmd('/ctrl /itemnotify "' .. move_slot .. '" leftmouseup')
                mq.delay(1000)
                mq.cmd('/ctrl /itemnotify "' .. craft_container ..
                           '" leftmouseup')
                mq.delay(1000)
                mq.cmd('/ctrl /itemnotify 32 leftmouseup')
            end
        end
    end
    if mq.TLO.Me.Inventory(32)() ~= craft_container then
        print(
            "\at[TCSNeXt]\ay[We Failed Somehow to put the portable container in slot 32, Routine TCN_Craft]")
        mq.exit()
    end

The potential issue is dropping another portable container above this one and that container getting filled with components :(

buuut that always exists if a portable container is not in a bag.. so a work around might be to stuff containers in bags.. ugh!

buuut, when you craft, it checks to see if anything is in the container and cleans it out and auto inv..

I would have gotten away with it, if it weren't for those meddling custom UI users!
 
Last edited:
for those that may not know..

run a Lua in a Lua with arguments

assert(loadfile("\\MQNext\\Lua\\TCN_god.Lua"))(2330)

run a MQ macro in Lua

mq.cmd('/mac tsc beginner pottery')

run a Lua in MQ macro

/Lua run code.Lua
 
The old way was ugly.. the new way is elegant..

The way it works, you send it a variable such as Toolbox, which is needed for the quest and if it has a Deluxe Toolbox it will return that, so you
don't have to buy a Toolbox and it provides the container name to use for crafting.

The short of it, you can use multiple containers, you don't have to use a Toolbox for the tinkering quests in GOD/TSS, It will auto-use a Deluxe Toolbox for you, same with Planar kits, and special voodoo medicine bags.

This is specifically for crafting that requires portable containers and can substitute a "higher" caliber container.

Code:
function library.return_available_container(p_name)
    local available_containers = {
        "Deluxe Toolbox", "Planar Fletching Kit", "Reinforced Medicine Bag",
        "Foldable Medicine Bag", "Marble Mortar and Pestle",
        "Planar Jeweler's Kit", "Reinforced Jeweler's Kit"
    }
    for x = 1, #available_containers do
        if string.match(available_containers[x], p_name) and
            mq.TLO.FindItemCount(available_containers[x])() > 0 then
            local m = available_containers[x]
            return m
        end
    end
end

For those that like pain: The old way

Code:
|Toolbox <> Swapper!
/if (${ContainerName.Equal[ToolBox]} && ${FindItemCount[=Deluxe Toolbox]} > 0) {
/varset ContainerName Deluxe Toolbox
}
|Fletching Kit <> Swapper!
/if (${ContainerName.Equal[Fletching Kit]} && ${FindItemCount[=Planar Fletching Kit]} > 0) {
/varset ContainerName Planar Fletching Kit
}
|Jewler's Kit <> Swapper!
/if (${ContainerName.Equal[Jeweler's Kit]} && (${FindItemCount[=Planar Jeweler's Kit]} > 0 || ${FindItemCount[=Reinforced Jeweler's Kit]} > 0)) {
/varset ContainerName ${FindItem[Jeweler's Kit]}
}
|Mortar and Pestle <> Swapper!
/if (${ContainerName.Equal[Mortar and Pestle]} && ${FindItemCount[=Marble Mortar and Pestle]} > 0) {
/varset ContainerName ${FindItem[Mortar and Pestle]}
}
|Medicine Bag <> Swapper!
/if (${ContainerName.Equal[Medicine Bag]} && (${FindItemCount[=Reinforced Medicine Bag]} > 0 || ${FindItemCount[=Foldable Medicine Bag]} > 0)) {
/varset ContainerName ${FindItem[Medicine Bag]}
}
 
Glad you're finding efficiencies to make the process work better. Out of curiosity, is there a reason to hard-code that list? Seems like making it an add-in Lua file (e.g., containers.Lua) is more maintainable long-term.
 
Glad you're finding efficiencies to make the process work better. Out of curiosity, is there a reason to hard-code that list? Seems like making it an add-in lua file (e.g., containers.lua) is more maintainable long-term.

This brings up some interesting set of questions..

The containers list will be quite small and maintained in a lib (tcn_library.Lua), so anytime it is needed it can be called. Is there a benefit to making another required file?

Also, when should one use assert? A lot of things in TCS happen over and over when it comes to crafting and data manipulation. Is it better to have required files for re-use or use assert? Also a lot of the required files depend on one another. The reason I did that was so I could make changes to one thing and a) not worry about affecting something else b) have smaller code to look at c) flexibility..

or does it not matter and I should just make 1 huge file and 1 library file?

some current flows: (names will change)

legacy quests (freebies currently) db and tcn_craft , tcn_god, tcn_library,tcn_movement

newer quests: db,tcn_craft, tcn_recipe_sort,tcn_quests, tcn_buy, tcn_library,tcn_movement

general trade skilling: db, tcn_craft, tcn_recipe_sort, tcn_buy, tcn_library,tcn_movement

and there will be a bind feeder program to start all these things..

TCN_movement handles, you guessed it, movement, but it will include things like boat rides, riding elevators, clicking switches..

I also did wonder if just making 1 file makes event handling easier..
 
Last edited:
One of the idea of separate files is to improve maintainability. In this case, a list of portable tradeskill containers is a resource. So is a list of reusable tools (file, smithy hammer, etc.) or stationary tradeskill containers. Having them separated makes it easier for you to bring them up quickly for modification and reference. I made my comment because you had the list defined within a function. Even if that function were located in your library file, I'd still encourage moving the list of available containers out of the function. Personally, I'd move them to a resources file, but even if you didn't want to create another file with those types of definitions, having them together in your library is still beneficial.

You are following this basic idea now within the TSC macro system by having the different areas of concern (core, god, pok, support, etc.) as separate files. A good code editor can help mitigate the management of this data/info in many ways, but the idea still remains. Make it easier on your future self by using good practices now.
 
Last edited:
One of the idea of separate files is to improve maintainability. In this case, a list of portable tradeskill containers is a resource. So is a list of reusable tools (file, smithy hammer, etc.) or stationary tradeskill containers. Having them separated makes it easier for you to bring them up quickly for modification and reference. I made my comment because you had the list defined within a function. Even if that function were located in your library file, I'd still encourage moving the list of available containers out of the function. Personally, I'd move them to a resources file, but even if you didn't want to create another file those types of definitions having them together in your library is still beneficial.

You are following this basic idea now within the TSC macro system by having the different areas of concern (core, god, pok, support, etc.) as separate files. A good code editor can help mitigate the management of this data/info in many ways, but the idea still remains. Make it easier on your future self by using good practices now.


My goal is to minimize pain in the future. I may collapse some down, if all the main routines use them.. (i.e, right now they all use craft, movement, and library)
 
As an example the legacy quest engine requires:

Code:
local mq = require('mq')
local mv = require('tcn_movement')
local lib = require('tcn_library')
local buy = require('tcn_buy')
local craft = require('tcn_craft')
local sqlite3 = require('lsqlite3complete')
local db = sqlite3.open('artisandb.db')

Which makes sense, because it is the main routine.. currently.

and yeah I don't know how to open a db anywhere, it always uses the root of the everquest folder for the db.. even after I tried // or \\ or '/' or mq.TLO.MacroQuest, etc..
 
Last edited:
I guess I need SQL 😅

I need to read more...


oh ya..

drop this in the root of Lua..

This is an UNOFFICIAL release of SQLite for testing purposes, not Redguide tested or approved..

It is hardcoded to be used in the Lua dir for now, until there is an official release and then I will hard code it to there + MacroQuest.Path()
 

Attachments

Last edited:
before I get too far into the weeds.. is this on the right path..

Code:
-- Search SQL Recipes
local function bind_search(...)
    local args = {...}
    if args[1] == nil then
        print "invalid input "
        return
    end
    mq.delay(1)
    local clean_arg = string.gsub(args[1], '"', '')
    if args[2] == "any" then
        clean_arg = '%' .. clean_arg .. '%'
    else
        clean_arg = clean_arg .. '%'
    end
    clean_arg = "'" .. clean_arg .. "'"
    search_recipes(clean_arg)
end
 
little ersatz demo..

yes I am typing but I move all windows around because I am paranoid..

and yes the intent is to make every darn recipe available to craft.. it has 43000+ , I need to do integrity checks but for the most part we are good


proposed Finished product:

it will also do artisan seals beginning to end with delivery, trade skill trophies ,beginning to end, any level beginner to master, TSS freebies, GOD Freebies, the quest I can never remember but it allows you to get the book or something from Kerst Frostriff or something and more.. Auto skillups, Auto destroys all the things, do the road to 350, grab plat from the bank as needed, buy materials as needed, and pretty much every recipe


Code Progress:

GOD 96%
Trade skill Engine 98%
TSS 0 %
Artisan Seals 20%
Trophies 10%
 

Attachments

Last edited:
Now with turbo handling

1632255179124.png

just run the quest from a menu.. no fuss no muss !


no more /Lua run tsc tss pottery or /mac tsc tss pottery..

now just /god 1
 
Last edited:
Craft by ID or craft by partial name with selection .. who needs limitations!

/craft Ka 1 presents this..

1632264773191.png

or /craft 18070 1 if you know the id already..

or you can use the built in search facility to search starting with or search for any occurrence of the search term

/search darkh

/search darkh any
 
Last edited:
Does this work the way I think it does..

I have a module loaded, I want it to reload, so that when I make a reference to it again , it will run the updated code I just changed behind the scenes? is that correct?

mymodule = require "mymodule"

--make some changes.. then trigger a reload

package.loaded.mymodule = nil
mymodule = require "mymodule"
 
no, require caches. You load it once, it will reference the loaded object that was previous loaded. What you want is loadfile (which is kind of broken right now, it's on my list when I can get some time...)
 
no, require caches. You load it once, it will reference the loaded object that was previous loaded. What you want is loadfile (which is kind of broken right now, it's on my list when I can get some time...)

Thank you...
 
Thank you for everyone who has indulged me, the rewards shall be great. well.. depending on your viewpoint..
 
Usually when I go back to look at old code I've written it's "What the hell was I thinking to write it that way?!?"
 
Usually when I go back to look at old code I've written it's "What the hell was I thinking to write it that way?!?"

I found this in an ini file .. and I have no idea what it is for and what I was thinking..

Code:
|get /Call Get_Item_Total "${ts_file}" ${rec_tick}
|for 1 to 2 do these other things..
|get item name /Call Get_Item_Name "${ts_file}" ${rec_tick} ${item_num}
|/Call Get_ Item_Count "${ts_file}" ${rec_tick} ${item_num} get item count
|get item vendor |call item match

For me I look back and say, how did I solve this problem, and then, was it a good solution..

function names.. well I admit I don't always have a good name for them.

function get_thing_that_does_stuff_and_return_things
 
Last edited:
working on this but it is draining my life force.. The ability to craft a recipe when it has multiple materials to complete it..

1632419858786.png

it will also try to make it by lowest yield, so if you have a 17 lb bass and a 1 lb bass it will pick the 1 lb bass first if you only need 1
 
Last edited:
Patience does pay off..


1632431875016.png

it successfully chose the right recipe based on available materials and yields and made it :)

However, if it is a small brick and it has 5 recipes, but the vendor has it for 1 cp I am going the vendor route as much as possible..

Also, if it has 5 recipes and 4 are crazy expensive, I will try to stick to 1..
 
Last edited:
just when I wanted to do something cool it don't work.. wanted to execute a string using loadstring.. no bueno!

it says deprecated.. :(
 
Last edited:
Code:
    -- Main Turn IN Loop
    for row in db:nrows(
                   "SELECT * FROM Quest_Table WHERE Quest_Step_Order =2 and Quest_Task_ID =" ..
                       p_quest_id) do
        local deliver_item_req = mq.TLO.Task(p_quest_title).Objective(
                                     row.Quest_Deliver_Step).RequiredCount()
        local deliver_item_cur = mq.TLO.Task(p_quest_title).Objective(
                                     row.Quest_Deliver_Step).CurrentCount()
        local fv_item_count = mq.TLO.FindItemCount(row.Quest_Item_ID)()
     
        if mq.TLO.Task(p_quest_title).Objective(row.Quest_Deliver_Step).Status() ~=
            "Done" then
            -- Items to turn in
            if mq.TLO.FindItemCount(row.Quest_Item_ID)() > 0 then
                local remaining_deliver_count = deliver_item_req -
                                                    deliver_item_cur
                local fv_turn_in = remaining_deliver_count
                if fv_item_count > remaining_deliver_count then
                    fv_turn_in = remaining_deliver_count
                end
                if fv_item_count ~= 0 and fv_item_count <
                    remaining_deliver_count then
                    fv_turn_in = fv_item_count
                end
                -- No-Stack
                if mq.TLO.FindItem(row.Quest_Item_ID).StackSize() == 1 and
                    remaining_deliver_count > 0 then
                    -- Item Inventory
                    fv_item_count = mq.TLO.FindItemCount(row.Quest_Item_ID)()
                    for x = 1, fv_turn_in do
                        lib.give_quest_item_id(row.Quest_Item_ID, 1)
                        mq.delay(100)
                    end
                else
                    -- Stacks
                    lib.give_quest_item_id(row.Quest_Item_ID, fv_turn_in)
                    mq.delay(100)
                end
            end
        end
    end
    mq.delay(1)
end

do your worst!.. simple way to turn in a items that are stackable or not.. uses task and database

I am lazy, I need to work on GiveWnd0 to make it even faster...maybe
 
just for those that may not know

determining if plugin is loaded.

Code:
-- Stop auto-forage
if mq.TLO.Plugin('mq2autoforage')() then
    print(msg, "\awDisabling: \agAuto-Forage")
    mq.cmd('/squelch /stopforage')
end
 
is this ok to do or should binds be limited?

mq.bind('/opt', bind_opt)
mq.bind('/menu', bind_menu)
mq.bind('/search', bind_search)
mq.bind('/craft', bind_craft)
mq.bind('/god', bind_god)
mq.bind('/dump', bind_dump)
mq.bind('/choice', bind_choice)
mq.bind('/trophies', bind_trophies)

are there concerns?
 
Lua - Lua Snips and discussion

Users who are viewing this thread

Back
Top
Cart