WoWInterface SVN NakasBot

[/] [trunk/] [NakasBot/] [NakasBot.lua] - Rev 3

Compare with Previous | Blame | View Log

-- The following encapsulates the Recipe database  27914

RecipeDB = {};

function GetRecipeDescription(name)
        if RecipeDB[name] == nil then
                return "<Invalid Recipe>"
        else
                return RecipeDB[name].Description
        end
end
function SetRecipeDescription(name, descr)
        if RecipeDB[name] == nil then
                RecipeDB[name] = {} end
        RecipeDB[name].Description = descr
end


function GetRecipeLink(name)
        if RecipeDB[name] == nil then
                return "<Invalid Recipe>"
        else
                return RecipeDB[name].Link
        end
end
function SetRecipeLink(name, link)
        if RecipeDB[name] == nil then
                RecipeDB[name] = {} end
        RecipeDB[name].Link = link
end


function GetRecipeMats(name)
        if RecipeDB[name] == nil then
                return "<Invalid Recipe>"
        else
                return RecipeDB[name].Mats
        end
end
function SetRecipeMats(name, mats)
        if RecipeDB[name] == nil then
                RecipeDB[name] = {} end
        RecipeDB[name].Mats = mats
end


function SetRecipeKeywords(name, words)
        if RecipeDB[name] == nil then
                RecipeDB[name] = {} end
        RecipeDB[name].Keywords = words
end
function GetRecipeDescription(name)
        if RecipeDB[name] == nil then
                return "<Invalid Recipe>"
        else
                return RecipeDB[name].Description
        end
end


-- The following functions encapsulate the Component database

bysComponentDB = {};

function SetComponentPrice(name, gold, silver, copper)
        if bysComponentDB[name] == nil then
                bysComponentDB[name] = {} end
        bysComponentDB[name].Price = gold*10000 + silver*100 + copper
end
function GetComponentPrice(name)
        if bysComponentDB[name] == nil then
                return 99,99,99
        else
                local copper = mod(bysComponentDB[name].Price, 100);
                local silver = mod(bysComponentDB[name].Price/100, 100);
                local gold = bysComponentDB[name].Price/10000;
                return gold, silver, copper;
        end
end




-----------------------------------------------------------------


function Id2Name(id)
        local longname,_,_,_,_ = ESell_Enchante_getInfoDetail(id);
        return longname
end
function Name2Id(name)
--      local longname,_,_,_,_ = ESell_Enchante_getInfoDetail(id);
--      return longname
end

squelches = {};
squelchCount = 0;

function SendSquelchedMessage(message, channel, arg3, who)
        squelchCount = squelchCount + 2;
        SendChatMessage(message, channel, arg3, who);
end

function Nakas_EditDB(text)
        local _, firstspace = strfind(text, " ", 1);
        local _, secondspace = strfind(text, ".*|h|r ", firstspace + 1);
        local _, thirdspace = strfind(text, " ", secondspace + 1);

        local link = strsub(text, firstspace + 1, secondspace-1);
        local key = strsub(text, secondspace + 1, thirdspace-1);
        local value = strsub(text, thirdspace + 1);

        ChatFrame1:AddMessage("link<"..link..">",0,1,1);
        ChatFrame1:AddMessage("key<"..key..">",0,1,1);
        ChatFrame1:AddMessage("value<"..value..">",0,1,1);
        
        for i, enchanteTable in ipairs(EnchantingSell_ListEnchante) do
                if link == enchanteTable.Link then
                        enchanteTable[key] = value;
                end
        end

end


function Nakas_AddEnchant(link)
        ESell_Enchante_AddEnchant(link);
end


function Nakas_Getlink(who, link)
                printable = gsub(link, "\124", "\124\124");
                ChatFrame1:AddMessage("Here's what it really looks like: \"" .. printable .. "\"");
end







function Nakas_KeywordsHelp(who)
        message1 = [[The search engine understands the following keywords:]];
        message2 = [[Recipe type & rarity:  enchant, gem, rare, meta]]
        message3 = [[Enchant locations:  chest, gloves, 1h, 2h, weapon, ...]]
        message4 = [[Base attributes: str, agil, stam, int, spirit]]
        message5 = [[Other attributs: spell, crit, damage, healing, stun, ...]]
        message6 = [[Gem colors:  red, orange, yellow, green, blue, purple]];
        message7 = [[Common gem names:  peridot, garnet, moonstone, ...]]
        message8 = [[Common gem cuts: inscribed, potent, shifting, ...]];
        message9 = [[Rare gem names:  topaz, ruby, skyfire, earthstorm, ...]];
        message10 = [[Rare gem cuts: enigmatic, destructive, brutal, ...]];

        SendSquelchedMessage(message1, "WHISPER", nil, who);
        SendSquelchedMessage(message2, "WHISPER", nil, who);
        SendSquelchedMessage(message3, "WHISPER", nil, who);
        SendSquelchedMessage(message4, "WHISPER", nil, who);
        SendSquelchedMessage(message5, "WHISPER", nil, who);
        SendSquelchedMessage(message6, "WHISPER", nil, who);
        SendSquelchedMessage(message7, "WHISPER", nil, who);
        SendSquelchedMessage(message8, "WHISPER", nil, who);
        SendSquelchedMessage(message9, "WHISPER", nil, who);
        SendSquelchedMessage(message10, "WHISPER", nil, who);
        
        ChatFrame1:AddMessage("Spamming keywords to: "..who,0,1,1);
end


-----------------------------------------------------------------------------------------------
local Nakas_LastWho = "";
local Nakas_LastMessage = "";
local arEnabled = true;
local arHideWhispersTimer = 0;
local OriginalChatFrame_OnEvent;

function NakasBot_OnLoad()
        this:RegisterEvent("CHAT_MSG_WHISPER");
        this:RegisterEvent("AUCTION_ITEM_LIST_UPDATE");

        SlashCmdList["NAKASBOT"] = NakasBot_SlashHandler;
        SLASH_NAKASBOT1 = "/NakasBot";
        SLASH_NAKASBOT2 = "/nb";
        
        local cf = getglobal("ChatFrame1");
    cf.Nakas_Orig_AddMessage = cf.AddMessage;
--    cf.AddMessage = Nakas_ChatFrame_AddMessage;
end


-- REVISIT: Rewrite to only squelch outgoing whisper replys, not all whispers.
-- See http://www.wowwiki.com/HOWTO:_Hook_Chat_Messages
--  CHAT_MSG_WHISPER          --  Incomming whispers
--  CHAT_MSG_WHISPER_INFORM   --  Outgoing whispers

function Nakas_ChatFrame_AddMessage(self,msg,a1,a2,a3,a4,a5,a6,a7,a8,a9)
        if strfind(msg, "[Nakas]") ~= nil then
                ChatFrame3:AddMessage("squelched:"..msg,1,0,0);
                return;
        end
        
        return self:Nakas_Orig_AddMessage(msg, a1,a2,a3,a4,a5,a6,a7,a8,a9);
end






function parse(text)
        local list = {}
        local pos = 1
        while 1 do
                local first, last = strfind(text, " ", pos)
                if first then
                        word = strsub(text, pos, first-1)
                        if word ~= "" then tinsert(list, word) end
                        pos = last+1
                else
                        word = strsub(text, pos)
                        if word ~= "" then tinsert(list, word) end
                        break
                end
        end
        return list
end





--local msg = "Phase2:- There isn't any need for iterating over this mini-string.";
--local startPos, endPos, firstWord, restOfString = string.find( msg, "(%w+)[%s%p]*(.*)");
--startPos = 1
--endPos = 66
--firstWord = "Phase2"
--restOfString = "There isn't any need for iterating over this mini-string."





--keywords = { "agility", "strength", "spirit", 
-- "fire", "nature", "shadow", "frost", "resist",
-- "intellect", "stamina", "weapon", "2h", "1h", "bracer",
-- "cloak", "chest", "boot", "glove", "shield", "fiery", "icy", "crusader", "might", "lifestealing",
-- "winter", "defense", "block", "healing", "heal", "spell", "demonslaying",
-- "power", "damage", "link", "resist", "resistance", "armor", "health", "mana",
-- "herbalism", "mining", "skinning", "riding", "skill", "speed", "brilliant", "wizard", "oil",
-- "assault", "spell", "crit", "brawn", "restore", "prime", "vitality", "tough", "attack", "power", "penetration" };


function Nakas_RepairString(what)
        repaired = "";

--      ChatFrame1:AddMessage("before: <"..what..">",0,1,1);

        what = gsub(what, "%%", "");
        what = gsub(what, "!", "");
        what = gsub(what, "%?", "");
        what = gsub(what, "how much for ", "");
        what = gsub(what, "how much ", "");     
        what = gsub(what, "do you have ", "");

        -- Take care of itemlinks
        what = gsub(what, "%]|h|r", "")
        what = gsub(what, "|.+%[", "")

        for i,word in ipairs(parse(what)) do
                if word == "dmg" then word = "damage" end
                if word == "firey" then word = "fiery" end
                if word == "spellpower" then word = "spell power" end
                if word == "ap" then word = "attack power" end

                repaired = repaired.." "..word;
        end

        repaired = strsub(repaired, 2);

--      ChatFrame1:AddMessage("repaired: <"..repaired..">",0,1,1);
--      for i, parseword in ipairs(parse(repaired)) do
--              ChatFrame1:AddMessage("  <"..parseword..">",0,1,1);
--      end


        return repaired;
end

function Nakas_GetShortDescription(recipie)

        if tonumber(recipie) == nil then
                return RecipeDB[recipie].ShortDescription;
        end
        
        if EnchantingSell_ListEnchante[recipie].ShortDescription ~= nil then
                return EnchantingSell_ListEnchante[recipie].ShortDescription
        end
        
        name, onthis, bonus, bonusnb = ESell_Enchante_getInfoBonus(recipie);
        longname,_,description,_,link = ESell_Enchante_getInfoDetail(recipie);
        price,_,_ = ESell_Enchante_getPrice(recipie);

        if onthis == "Rod" or onthis == nil or bonus == nil then
                EnchantingSell_ListEnchante[recipie].ShortDescription = "Some Rod...";
        end
        
        if onthis == "Oil" then
                EnchantingSell_ListEnchante[recipie].ShortDescription = "Some Oil...";
        end

        if bonusnb == nil then
                EnchantingSell_ListEnchante[recipie].ShortDescription = bonus.." to "..onthis;
        else
                EnchantingSell_ListEnchante[recipie].ShortDescription = "+"..bonusnb.." "..bonus.." to "..onthis;
        end
        
        return EnchantingSell_ListEnchante[recipie].ShortDescription;   
end     





function Nakas_GetKeywords(recipie)

--      ChatFrame1:AddMessage(recipie,0,1,1);

        if tonumber(recipie) == nil then
                return RecipeDB[recipie].Keywords;
        end
        
        if EnchantingSell_ListEnchante[recipie].Keywords == nil then
                EnchantingSell_ListEnchante[recipie].Keywords = gsub(strlower(Nakas_GetShortDescription(recipie)),"%+","");     
        end     
        return EnchantingSell_ListEnchante[recipie].Keywords;
end     


function Nakas_GetLink(recipe)
        if tonumber(recipe) == nil then
                return RecipeDB[recipe].Link;
        else
                return EnchantingSell_ListEnchante[recipe].Link;
        end
end     


function Nakas_GetPrice(recipe)
        if tonumber(recipe) == nil then
                return RecipeDB[recipe].Price;
        else
                price,_,_ = ESell_Enchante_getPrice(recipe);
                return price/10000;
        end
end

function Nakas_DisplayMatches(matches, who)
        ChatFrame1:AddMessage("Displaying Matches ("..getn(matches).." found)",0,1,1);
        if getn(matches) == 0 then
                SendSquelchedMessage("> No matches found", "WHISPER", nil, who);
                return;
        end

        SendSquelchedMessage("> =========<<  Search Results  >>=========", "WHISPER", nil, who);
        for i, recipe in ipairs(matches) do
                short_description = Nakas_GetShortDescription(recipe);
                link              = Nakas_GetLink(recipe);
                price             = Nakas_GetPrice(recipe);
                                
                if price >= 3 then
                        if price >= 10000 then
                                SendSquelchedMessage("> "..link.."   "..short_description, "WHISPER", nil, who);
                        else
                                SendSquelchedMessage("> "..link.."   "..short_description.." ("..price.."g+tip)", "WHISPER", nil, who);
                        end
                end
                if i > 20 then
                        SendSquelchedMessage("> Displaying first 20 matches ("..getn(matches).." found).  Use more keywords to limit the search", "WHISPER", nil, who);
                        break;
                end

        end
        SendSquelchedMessage("> I am currently in: "..GetZoneText(), "WHISPER", nil, who);
        arHideWhispersTimer = GetTime();
end



-- The word matches the recipe if:
--   a) The word is 3 or more letters and matches the beginning of a keyword
--   b) The word is a number and is an exact match to a keyword

function Nakas_WordMatchesRecipe(word, recipe)
        local keywords = strlower(Nakas_GetKeywords(recipe));
    -- If the word is fewer than 3 characters, a full match is required
        if strlen(word) < 3 then
                for i, keyword in ipairs(parse(keywords)) do
                        if keyword == word then
                                return true;
                        end
                end
        else  -- otherwise a match to the front of the keyword is required
                for i, keyword in ipairs(parse(keywords)) do
                        if strfind(keyword, word,1,true) == 1 then
                                return true;
                        end
                end
        end
        
        return false;
end



function Nakas_GetBestMatches(searchstring)
        local best_matches = {};
        local max_matches = 0;
        local searchset = parse(searchstring);

        for name, recipe in pairs(RecipeDB) do
                matches = 0;
                for i, word in ipairs(searchset) do
                        if Nakas_WordMatchesRecipe(word, name) then
                                matches = matches + 1;
--                              ChatFrame1:AddMessage("match:"..name,0,1,1);
                        end
                end
                
                if matches > max_matches then
                        max_matches = matches;
                        best_matches = {};
                end     

                if matches == max_matches then
                        tinsert(best_matches, name);
                end
        end

--      ChatFrame1:AddMessage("max_matches:"..max_matches,0,1,1);
--      ChatFrame1:AddMessage("getn(searchset):"..getn(searchset),0,1,1);

        if max_matches * 2 > getn(searchset) then
                return best_matches;
        else
                return nil
        end
end


-- Sorting function
function Nakas_EnchantCostsMore(a, b)
        return  Nakas_GetPrice(a) > Nakas_GetPrice(b);
end


function Nakas_HelpMenu(who)
        message1 = [[Welcome to Nakas' Enchanting & Jewelcrafting search engine!]];
        message2 = [[Please choose from the following options:]];
        message3 = [[    "search" - Describes how to use the search engine.]];
        message4 = [[    "mats" - Gives the prices of mats and describes how prices are calculated.]];
        message5 = [[    "tips" - Info on tipping]];
        message6 = [[    "new" - Lists my new Outlands enchants]];
        message7 = [[    "keywords" - Lists the keywords that the search engine recognizes]];
        message8 = [[]];
        message9 = [[Feel free to add me to your friends list and use the search engine anytime!]]
        
        SendSquelchedMessage(message1, "WHISPER", nil, who);
        SendSquelchedMessage(message2, "WHISPER", nil, who);
        SendSquelchedMessage(message3, "WHISPER", nil, who);
        SendSquelchedMessage(message4, "WHISPER", nil, who);
        SendSquelchedMessage(message5, "WHISPER", nil, who);
        SendSquelchedMessage(message6, "WHISPER", nil, who);
        SendSquelchedMessage(message7, "WHISPER", nil, who);
        SendSquelchedMessage(message8, "WHISPER", nil, who);
        SendSquelchedMessage(message9, "WHISPER", nil, who);
        
        ChatFrame1:AddMessage("Spamming help to: "..who,0,1,1);
        arHideWhispersTimer = GetTime();
end


function Nakas_SearchHelpMenu(who)
        message1 = [[The search engine looks for keywords in your whisper, words like "agil", "fiery", "gloves", "+7", etc.  If more than 50% of the words in your whisper are keywords, it will assume your whisper is a query.]];
        message2 = [[It will look for enchants that match the most number of words by comparing your whisper with the name of the enchant and the description text within the link.]];
        message3 = [[Therefore, try not to have extra words in your whisper.  For example, the whisper "+25 agility" will trigger the search engine, but the whisper "What do you charge for +25 agility" will not because most of the words are not keywords.]]

        SendSquelchedMessage(message1, "WHISPER", nil, who);
        SendSquelchedMessage(message2, "WHISPER", nil, who);
        SendSquelchedMessage(message3, "WHISPER", nil, who);
        
        ChatFrame1:AddMessage("Spamming search help to: "..who,0,1,1);
        arHideWhispersTimer = GetTime();
end


NewEnchantList = { 
  "Enchant Bracer - Brawn", 
  "Enchant Bracer - Assault", 
  "Enchant Chest - Restore Mana Prime",
  "Enchant Bracer - Stats", 
  "Enchant Chest - Exceptional Health",
  "Enchant Cloak - Greater Agility",
  "Enchant Cloak - Major Armor",
  "Enchant Gloves - Assault",
  "Enchant Shield - Tough Shield",
  "Enchant Bracer - Major Intellect",
  "Enchant Gloves - Blasting",
  "Enchant Shield - Major Stamina",
  "Enchant Shield - Intellect",
  "Enchant Cloak - Spell Penetration",
  "Enchant Bracer - Superior Healing",
  "Enchant Weapon - Major Spellpower",
  "Enchant Weapon - Major Intellect",
  "Enchant Bracer - Spellpower",
  "Enchant Gloves - Major Spellpower",
  "Enchant Gloves - Major Strength",
  }

function Nakas_NewMenu(who)
        message1 = [[Here is a list of the new Burning Crusade enchants that I can do:]]
        SendSquelchedMessage(message1, "WHISPER", nil, who);

        matches = {};

        for i, enchant in ipairs(EnchantingSell_ListEnchante) do
                for j, newEnchant in ipairs(NewEnchantList) do
                    if enchant["LongName"] == newEnchant then
                                tinsert(matches, i);
                        end
                end
        end
        
        sort(matches, Nakas_EnchantCostsMore);
        Nakas_DisplayMatches(matches, who);

        ChatFrame1:AddMessage("Spamming new help to: "..who,0,1,1);
        arHideWhispersTimer = GetTime();
end


function Nakas_MatsHelpMenu(who)
        message1 = [[The prices of the enchants are auto-calculated from the average AH price of the required mats.]]
        message2 = [[If you supply your own mats, the price will be discounted appropriatly.  If you provide all the mats, you'll only be responsible for the tip]]
        message3 = [[The price of mats can vary from day to day with the market, so please don't be too upset if they're a little off.  Currently, the prices for some of the more expensive mats are set as follows:]]
        SendSquelchedMessage(message1, "WHISPER", nil, who);
        SendSquelchedMessage(message2, "WHISPER", nil, who);
        SendSquelchedMessage(message3, "WHISPER", nil, who);
                
        for i, mat in ipairs(EnchantingSell_ListComponant) do
                price = mat.PriceUnite / 10000;
                name = mat.Name;

--              ChatFrame1:AddMessage(name,0,1,1);

                inBag, inBank, onAlt = ESell_Reagent_getCount(i, player);
                inStock = inBag + inBank;
                if price > 3 and 
                        (strfind(name,"Essence") ~= nil or
                         strfind(name,"Shard") ~= nil or
                         strfind(name,"Dust") ~= nil or 
                         strfind(name,"Orb") ~= nil or 
                         strfind(name,"Primal") ~= nil) then

                        link = EnchantingSell_ListComponant[i]["Link"];
                                                        
                        SendSquelchedMessage(">"..link.."    "..price.."g      ("..inStock.." in stock)", "WHISPER", nil, who);
                end
        end
                
        ChatFrame1:AddMessage("Spamming mats help to: "..who,0,1,1);
        arHideWhispersTimer = GetTime();
end


function Nakas_TipsHelpMenu(who)
        message1 = [[The prices quoted are given as a gold amount plus a tip.  The gold amount is the market value of the mats, the tip is the gratuity for doing the enchant.  In general, tipping is not optional, a few gold tip is considered minimum for any enchant.]];
--      message2 = [[In general, tipping is not optional, a few gold tip is considered minimum for any enchant.]]
        message3 = [[The guidelines for specific popular enchants/cuts are:]]
        message4 = [[  15-25g:   +22 Intellect]];
        message5 = [[  10-20g:   Spellpower, Healing power, Lifestealing, +5 1h Damage]]
        message6 = [[  5-15g:    Crusader, +25 Agil, +15 Agil, 2% block, +15 resist]]
        message7 = [[  2-5g:     Cutting green quality gems]]
        message8 = [[  10-15g:   Cutting blue quality gems]]
        message9 = [[For other enchants, the general rule of thumb is 10% the price of mats, with a few gold minimum.]]

        SendSquelchedMessage(message1, "WHISPER", nil, who);
--      SendSquelchedMessage(message2, "WHISPER", nil, who);
        SendSquelchedMessage(message3, "WHISPER", nil, who);
        SendSquelchedMessage(message4, "WHISPER", nil, who);
        SendSquelchedMessage(message5, "WHISPER", nil, who);
        SendSquelchedMessage(message6, "WHISPER", nil, who);
        SendSquelchedMessage(message7, "WHISPER", nil, who);
        SendSquelchedMessage(message8, "WHISPER", nil, who);
        SendSquelchedMessage(message9, "WHISPER", nil, who);

        ChatFrame1:AddMessage("Spamming tips help to: "..who,0,1,1);
        arHideWhispersTimer = GetTime();
end


        

function Nakas_ListAllGems()
        string = "";
        for name, recipe in pairs(RecipeDB) do
        
                ChatFrame1:AddMessage(GetItemCount(recipe.Link).."   "..recipe.Link);
        end
        
end


function NakasBot_OnEvent(event)
        if (event == "CHAT_MSG_WHISPER") then
        
                local what = string.lower(arg1);
                local who = arg2;

                -- spam filter
                --if UnitLevel(who) == 1 then
                --      ChatFrame1:AddMessage("Message from "..who.." blocked",1,0,0);
                --      return;
                --end
                
                if (arEnabled == false) then
--                      ChatFrame1:AddMessage("> ".."disabled",1,0,0);
                        return;
                end
                if (strfind(what,">") == 1) then
--                      ChatFrame1:AddMessage("> ".."bracket found",1,0,0);
                        return;
                end
                if strfind(what, "help") == 1 then
                        Nakas_HelpMenu(who);
                end
                if strfind(what, "search") == 1 then
                        Nakas_SearchHelpMenu(who);
                end
                if strfind(what, "mats") == 1 then
                        Nakas_MatsHelpMenu(who);
                end
                if strfind(what, "tips") == 1 then
                        Nakas_TipsHelpMenu(who);
                end
                if strfind(what, "new") == 1 then
                        Nakas_NewMenu(who);
                end
                if strfind(what, "getlink") == 1 then
                        Nakas_Getlink(who, arg1);
                end
                if strfind(what, "keyword") == 1 then
                        Nakas_KeywordsHelp(who);
                end
                if strfind(what, "editdb") == 1 then
                        Nakas_EditDB(arg1);
                end             
                if strfind(what, "addenchant") == 1 then
                        Nakas_EditDB(arg1);
                end
                if strfind(what, "listall") == 1 then
                        Nakas_ListAllGems(arg1);
                end

                what = Nakas_RepairString(what);

--              ChatFrame1:AddMessage("> Original string: ["..arg1.."]",1,0,0);
--              ChatFrame1:AddMessage("> Repaired string: ["..what.."]",1,0,0);

                matches = Nakas_GetBestMatches(what);
                if matches ~= nil then
                        ChatFrame1:AddMessage("> "..who..": "..arg1,1,0,0);
                        sort(matches, Nakas_EnchantCostsMore);
                        Nakas_DisplayMatches(matches, who);
                else
                        Nakas_LastWho = who;
                        Nakas_LastMessage = what;
                end
        end
end



function NakasBot_SlashHandler(arg1)
        if (arg1 == "on") then
                arEnabled = true;
                ChatFrame1:AddMessage("NakasEnchant enabled");
                return;
        end
        
        if (arg1 == "off") then
                arEnabled = false;
                ChatFrame1:AddMessage("NakasEnchant disabled");
                return;
        end
        
        if (arg1 == "reply") then
                matches = Nakas_GetBestMatches(Nakas_LastMessage);
                sort(matches, Nakas_EnchantCostsMore);
                Nakas_DisplayMatches(matches, Nakas_LastWho);
        end
end


Compare with Previous | Blame