--[[ * The MIT License (MIT) * * Copyright (c) 2014 MalRD * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ]]-- _addon.author = 'MalRD, zombie343'; _addon.name = 'Find'; _addon.version = '3.2.0'; local slips = require('slips'); local STORAGES = { [1] = { id=0, name='Inventory' }, [2] = { id=1, name='Safe' }, [3] = { id=2, name='Storage' }, [4] = { id=3, name='Temporary' }, [5] = { id=4, name='Locker' }, [6] = { id=5, name='Satchel' }, [7] = { id=6, name='Sack' }, [8] = { id=7, name='Case' }, [9] = { id=8, name='Wardrobe' }, [10]= { id=9, name='Safe 2' }, [11]= { id=10, name='Wardrobe 2' }, [12]= { id=11, name='Wardrobe 3' }, [13]= { id=12, name='Wardrobe 4' }, [14]= { id=13, name='Wardrobe 5' }, [15]= { id=14, name='Wardrobe 6' }, [16]= { id=15, name='Wardrobe 7' }, [17]= { id=16, name='Wardrobe 8' } }; local default_config = { language = 0 }; local config = default_config; local inventory = AshitaCore:GetDataManager():GetInventory(); local resources = AshitaCore:GetResourceManager(); local MINSLIP = 1; local MAXSLIP = #slips.ids; ------------------------------------------------------------------------------- --Returns the real ID and name for the given inventory storage index. -- ------------------------------------------------------------------------------- local function getStorage(storageIndex) return STORAGES[storageIndex].id, STORAGES[storageIndex].name; end ------------------------------------------------------------------------------- ashita.register_event('load', function() end ); ------------------------------------------------------------------------------- ashita.register_event('unload', function() end ); ------------------------------------------------------------------------------- -- func : printf -- desc : Because printing without formatting is for the birds. ------------------------------------------------------------------------------- function printf(s,...) print(s:format(...)); end; ------------------------------------------------------------------------------- -- func: find -- desc: Attempts to match the supplied cleanString to the supplied item. -- args: item -> the item being matched against. -- cleanString -> the cleaned string being searched for. -- useDescription -> true if the item description should be searched. -- returns: true if a match is found, otherwise false. ------------------------------------------------------------------------------- local function find(item, cleanString, useDescription) if (item == nil) then return false end; if (cleanString == nil) then return false end; if (string.lower(item.Name[config.language]):find(cleanString)) then return true; elseif (item.LogNameSingular[config.language] ~= nil and string.lower(item.LogNameSingular[config.language]):find(cleanString)) then return true; elseif (item.LogNamePlural[config.language] ~= nil and string.lower(item.LogNamePlural[config.language]):find(cleanString)) then return true; elseif (useDescription and item.Description ~= nil and item.Description[config.language] ~= nil) then return (string.lower(item.Description[config.language]):find(cleanString)); end return false; end ------------------------------------------------------------------------------- -- func: search -- desc: Searches the player's inventory for an item that matches the supplied -- string. -- args: searchString -> the string that is being searched for. -- useDescription -> true if the item description should be searched. ------------------------------------------------------------------------------- local function search(searchString, useDescription) if (searchString == nil) then return; end local cleanString = ParseAutoTranslate(searchString, false); if (cleanString == nil) then return; end cleanString = string.lower(cleanString); printf("\30\08Finding \"%s\"...", cleanString); local inventory = AshitaCore:GetDataManager():GetInventory(); local resources = AshitaCore:GetResourceManager(); local found = { }; local result = { }; local storageSlips = { }; for k,v in ipairs(STORAGES) do local foundCount = 1; for j = 0, inventory:GetContainerMax(v.id), 1 do local itemEntry = inventory:GetItem(v.id, j); if (itemEntry.Id ~= 0 and itemEntry.Id ~= 65535) then local item = resources:GetItemById(itemEntry.Id); if (item ~= nil) then if (find(item, cleanString, useDescription)) then quantity = 1; if (itemEntry.Count ~= nil and item.StackSize > 1) then quantity = itemEntry.Count; end if result[k] == nil then result[k] = { }; found[k] = { }; end if found[k][itemEntry.Id] == nil then found[k][itemEntry.Id] = foundCount; result[k][foundCount] = { name = item.Name[config.language], count = 0 }; foundCount = foundCount + 1; end result[k][found[k][itemEntry.Id]].count = result[k][found[k][itemEntry.Id]].count + quantity; end if find(item, 'storage slip ', false) then storageSlips[#storageSlips + 1] = {item, itemEntry}; end end end end end local total = 0; for k,v in ipairs(STORAGES) do if result[k] ~= nil then storageID, storageName = getStorage(k); for _,item in ipairs(result[k]) do quantity = ''; if item.count > 1 then quantity = string.format('[%d]', item.count) end printf('%s: %s %s', storageName, item.name, quantity); total = total + item.count; end end end for k,v in ipairs(storageSlips) do local slip = resources:GetItemById(v[1].ItemId); local slipItems = slips.items[v[1].ItemId]; local extra = v[2].Extra; for i,slipItemID in ipairs(slipItems) do local slipItem = resources:GetItemById(slipItemID); if (find(slipItem, cleanString, useDescription)) then local byte = extra[math.floor((i - 1) / 8)]; if byte < 0 then byte = byte + 256; end if (hasBit(byte, bit((i - 1) % 8 + 1))) then printf('%s: %s', slip.Name[config.language], slipItem.Name[config.language]); total = total + 1; end end end end printf('\30\08Found %d matching items.', total); end ------------------------------------------------------------------------------- function bit(p) return 2 ^ (p - 1); end ------------------------------------------------------------------------------- function hasBit(x, p) return x % (p + p) >= p; end local function findinslip(searchslip, item) if (item == nil) then return nil,nil end; if searchslip == 0 then for k,v in pairs(slips.items) do local slip = resources:GetItemById(k); for x = 1, #v do if item.Id == v[x] then local slipItem = resources:GetItemById(item.Id); --printf('%s: %s', slip.Name[config.language], slipItem.Name[config.language]); return slip.Name[config.language], slipItem.Name[config.language]; end end end elseif searchslip >= MINSLIP and searchslip <= MAXSLIP then local slip = resources:GetItemById(slips.ids[searchslip]); for x = 1, #slips.items[slips.ids[searchslip]] do if item.Id == slips.items[slips.ids[searchslip]][x] then local slipItem = resources:GetItemById(item.Id); --printf('%s: %s', slip.Name[config.language], slipItem.Name[config.language]); return slip.Name[config.language], slipItem.Name[config.language]; end end else printf('\30\08Please enter a valid storage slip between %i and %i, inclusive.', MINSLIP, MAXSLIP); end return nil,nil; end ------------------------------------------------------------------------------- local function getFindArgs(cmd) if (not cmd:find('/find', 1, true)) then return nil; end local indexOf = cmd:find(' ', 1, true); if (cmd:find('/findslips', 1, true) or cmd:find('/finddupes', 1, true)) and indexOf == nil then cmdTable = { [1] = cmd }; return cmdTable; end --Specific /findxyz command inputs that require second argument but don't have one specified if indexOf == nil then return nil; end --All other inputs that have /find and a space " ", return both words: cmdTable = { [1] = cmd:sub(1,indexOf-1), [2] = cmd:sub(indexOf+1), }; return cmdTable; end ------------------------------------------------------------------------------- -- func: printslips -- desc: Searches the player's inventory for any items that can be stored in -- storage slips. -- -- args: searchslip -> Indicates search all slips (0) OR specifies slip to -- search for (1-27 index into slip_data:slip.items[]) ------------------------------------------------------------------------------- local function printslips(searchslip) local found = { }; local foundSlip, foundItem; local result = { }; local keyset = {}; if searchslip == 0 then printf('\30\08Searching for any items that can be stored on any storage slips...'); elseif searchslip >= MINSLIP and searchslip <= MAXSLIP then printf('\30\08Searching for any items that can be stored on Storage Slip #%i...', searchslip); else printf('\30\08Please enter a valid storage slip between %i and %i, inclusive.', MINSLIP, MAXSLIP); return; end for k,v in ipairs(STORAGES) do for j = 0, inventory:GetContainerMax(v.id), 1 do local itemEntry = inventory:GetItem(v.id, j); if (itemEntry.Id ~= 0 and itemEntry.Id ~= 65535) then local item = resources:GetItemById(itemEntry.Id); if (item ~= nil) then --printf('%s: %s', item.Name[config.language], itemEntry.Id) foundSlip,foundItem = findinslip(searchslip, itemEntry) if (foundSlip ~= nil) then --keyset[#keyset+1] = foundSlip --printf('%s: %s', foundSlip, foundItem) --result[foundSlip] = foundItem; --table.insert(found, foundItem) if result[foundSlip] == nil then result[foundSlip] = {} table.insert(result[foundSlip], foundItem); keyset[#keyset+1] = foundSlip --result[foundSlip][itemEntry] = {}; else table.insert(result[foundSlip], foundItem); --result[foundSlip].itemEntry = item.Name end end end end end end --table.sort() local keysize = #keyset; local resultsize = 0; if keysize > 0 then table.sort(keyset) for slipIndex=1, keysize, 1 do for _,item in pairs(result[keyset[slipIndex]]) do printf('%s: %s', keyset[slipIndex],item); resultsize = resultsize + 1; end end if searchslip == 0 then printf("\30\08Found %i occurrence(s) of storable items in %i slips.", resultsize, keysize); else printf("\30\08Found %i occurrence(s) of storable items in storage slip #%i.", resultsize, searchslip); end else printf('\30\08No slip-storable items found.'); end end ------------------------------------------------------------------------------- -- func: printdupes -- desc: Searches the player's inventory for items that occupy more than one -- inventory slot. (Note, stacks or single items will both count as 1. -- Therefore, 2 stacks of 99 HP-Bayld will have a count of 2.) -- -- args: none -- ------------------------------------------------------------------------------- local function printdupes() local result = { }; local dupes = {}; local resultsize = 0; local dupesize = 0; printf('\30\08Searching for duplicate items...'); for k,v in ipairs(STORAGES) do for j = 0, inventory:GetContainerMax(v.id), 1 do local itemEntry = inventory:GetItem(v.id, j); if (itemEntry.Id ~= 0 and itemEntry.Id ~= 65535) then local item = resources:GetItemById(itemEntry.Id); if (item ~= nil) then if result[item.ItemId] == nil then result[item.ItemId] = 1; else cnt = result[item.ItemId] + 1 result[item.ItemId] = cnt; if cnt == 2 then resultsize = resultsize + 1; end end --printf('(itemName)=%s: (itemID):%s, (result[itemID]):%s', item.Name[config.language], item.ItemId, result[item.ItemId]); end end end end dupesize = 0; if (resultsize > 0) then for id,cnt in pairs(result) do if ( tonumber(cnt) > 1 ) then --printf('I %s: %d', id, cnt); local dupeitem = resources:GetItemById(id); dupes[id] = { name = dupeitem.Name[config.language], count=cnt }; dupesize = dupesize + 1; end end end if (dupesize > 0) then for k,v in pairs(dupes) do printf('%s: %d', v.name, v.count); end printf("\30\08Found %i occurrence(s) of duplicate items.", dupesize); else printf('\30\08No duplicate items found.'); return true; end end ------------------------------------------------------------------------------- ashita.register_event('command', function(cmd, nType) local args = getFindArgs(cmd); if (args == nil) then return false; end if (args[1]:lower() == '/find' and #args <= 2) then search(args[2]:lower(), false); return true; elseif (args[1]:lower() == '/findmore' and #args <= 2) then search(args[2]:lower(), true); return true; elseif (args[1]:lower() == '/finddupes' and #args <= 1) then printdupes(); return true; elseif (args[1]:lower() == '/findslips' and #args <= 2) then if #args >= 2 then searchslip = tonumber(args[2]:lower()); if not searchslip then printf('\30\08Please enter a valid storage slip between %i and %i, inclusive.', MINSLIP, MAXSLIP); return false; else printslips(searchslip); return true; end else printslips(0); end end; return false; end );