Allows searching for items within a players various storage containers via a slash command. http://ashita.atom0s.com/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

438 lines
17 KiB

--[[
* 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 );