|
Organizer!
Carbuncle.Akivatoo
サーバ: Carbuncle
Game: FFXI
Posts: 263
By Carbuncle.Akivatoo 2015-06-14 02:03:01
just an little to thanks you again for this pretty usefull addon
サーバ: Odin
Game: FFXI
Posts: 7
By Odin.Norriko 2015-06-17 04:21:06
Hey I'm having problems with 1 of my Characters with Organizer.
My Alt works just fine but when i try to use it on my Main Organizer starts and then i get this error message
Organizer: Lua runtime error: libs/exdata.lua:1388: attempt to index flied 'potency' (a nil value)
Main and Alt use similar Gearswap files so all i can think of is an Augment that cant be read.
did set Organizer on verbose but only gives the message Organizer: Starting... and then ends without doing anything.
Doesnt work on any Job for my Main and on all for my Alt.
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-17 06:22:09
Hey I'm having problems with 1 of my Characters with Organizer.
My Alt works just fine but when i try to use it on my Main Organizer starts and then i get this error message
Organizer: Lua runtime error: libs/exdata.lua:1388: attempt to index flied 'potency' (a nil value)
Main and Alt use similar Gearswap files so all i can think of is an Augment that cant be read.
did set Organizer on verbose but only gives the message Organizer: Starting... and then ends without doing anything.
Doesnt work on any Job for my Main and on all for my Alt.
Yeah, definitely an augment. Can you send me what's in your inventory? I'd like to see what's causing the choke.
Actually, does your main have a New Linkshell? That was causing augment chokes a while ago, and needs to be fixed.
サーバ: Odin
Game: FFXI
Posts: 7
By Odin.Norriko 2015-06-17 13:37:00
Will send you inventory stuff when I get back home. Cant be a Linkshell since both chars got the same pearls so I doubt its that.
You only need stuff from inventory or all of my Mh stuff as well?
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-17 13:45:48
Will send you inventory stuff when I get back home. Cant be a Linkshell since both chars got the same pearls so I doubt its that.
You only need stuff from inventory or all of my Mh stuff as well?
Everything, actually. If you //org freeze with no arguments it'll give you a full dump across several directories.
And I mean literally "New Linkshell", the item, as there's something in it that wigs out the augment parser (and it's been low priority enough that I haven't fixed it).
サーバ: Odin
Game: FFXI
Posts: 7
By Odin.Norriko 2015-06-17 14:19:45
when i type //org freeze i'm getting the same error as above.
and as i was browsing through Organizer folders only Inventory and Warrobe contain Lua files
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-17 14:22:15
when i type //org freeze i'm getting the same error as above
Ok, around line 82-83 of organizer.lua, there will be a _debugging structure. Set "items" to true, reload organizer, and run it again.
There will be a file created in data. Can you give me the last 10-12 lines of that?
サーバ: Odin
Game: FFXI
Posts: 7
By Odin.Norriko 2015-06-17 14:24:35
wrong log
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-17 14:28:34
Err, no. In Windower\addons\organizer\data, there should be a file called organizer-debug.log
The last lines of that are what I need. Actually, give me the first ten and the last ten, if you can.
サーバ: Odin
Game: FFXI
Posts: 7
By Odin.Norriko 2015-06-17 14:30:38
sry my fault
Organizer loaded at 06/17/15 21:29:22
2015-06-17 21:29:22| Organizer [VERBOSE] Adding inventory to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding satchel to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding sack to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding safe to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding wardrobe to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding storage to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding locker to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding safe2 to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding case to the pull list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding safe to the push list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding locker to the push list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding satchel to the push list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding storage to the push list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding sack to the push list
2015-06-17 21:29:22| Organizer [VERBOSE] Adding safe2 to the push list
2015-06-17 21:30:11| Organizer [MSG] Starting...
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-17 14:34:01
Err, my mistake, forgot something.
Line 94 in Windower\addons\organizer\organizer.lua, that enabled needs to be "true". Change that, reload organizer, run //org freeze, and then give me the first/last ten lines of that debug log.
サーバ: Odin
Game: FFXI
Posts: 7
By Odin.Norriko 2015-06-17 14:37:20
first ten would be same as above
last would be
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=45 item_table.id=11290 (Tidal Talisman)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=46 item_table.id=15740 (Shadow Sabatons)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=47 item_table.id=27923 (Councilor's Garb)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=48 item_table.id=27017 (Bagua Mitaines +1)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=49 item_table.id=27985 (Geo. Mitaines +1)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=50 item_table.id=28055 (Hagondes Cuffs)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=51 item_table.id=27192 (Bagua Pants)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=52 item_table.id=27235 (Telchine Braconi)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=53 item_table.id=27236 (Helios Spats)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=54 item_table.id=28135 (Assid. Pants +1)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=55 item_table.id=28159 (Artsieq Hose)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=56 item_table.id=26813 (Cab. Surcoat +1)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=57 item_table.id=28460 (Cetl Belt)
2015-06-17 21:35:26| Organizer [DEBUG] [items]: Items.new: inventory_index=58 item_table.id=17765 (Concordia)
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-17 14:39:39
What augments do you have on Concordia?
Err, the first ten shouldn't be exactly the same. Can you PM me like, a big chunk of the end of that file? We don't need to keep spamming the thread with it, I was hoping it'd be easy.
サーバ: Odin
Game: FFXI
Posts: 7
By Odin.Norriko 2015-06-17 14:42:04
send you the full log
as for Concordia it just has 2 blank augment lines no evolits attachet to it
Problem solved. Removed Evolit slots from Concordia everything fine now.
By Luminohelix 2015-06-17 15:42:16
Norri :3
Asura.Finbar
サーバ: Asura
Game: FFXI
Posts: 86
By Asura.Finbar 2015-06-18 12:37:59
Found an unusual glitch. If I have a Glowing Lamp in my inventory (a used one in this case, from a solo loss), I get a lua runtime error.
It specifically reflects line 1729 of extdata.lua from the the libs folder, which attempts to index global 'rettab' (a nil value). My guess it has something to do with the expended state of a used lamp (line 1723 regards Lamp data, and an expended lamp has no data). Not sure if this is a Windower error or Organizer error, but it only affected Organizer for me.
Obviously throwing the lamp away nulled the error, but I'm not sure why it was there in the first place.
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-18 12:46:46
So, the extdata lib is what parses augments. Anything that isn't part of standard, static item information (like time remaining on an old-school hourglass, the chamber name on a lamp, etc) uses the augment system just like actual augmented weapons. There are cases for a lot of these handled down in there; bonanza marbles and linkshells fall into this, for example.
However, all of those things require different handling, so any case that isn't explicitly handled has a chance to break. Norriko's problem was that the augments on Concordia (the old evolith weapon) look different than other kinds. New Linkshells break it too. I got the parts for a Concordia (just need to find the crafters to help synergize it) so I can sort out how that works, and I need to fix New Linkshell as well (though people don't generally carry those for long, so it's less pressing).
It isn't a bug with Organizer at all, but we see it pop up there because it's looking through and gathering information about your entire inventory. Gearswap is the other big user of extdata and it obviously doesn't care about lamps, etc. So it shows up now, and that means it's time to fix it. Thanks for giving me another test case!
サーバ: Asura
Game: FFXI
Posts: 59
By Asura.Orangebear 2015-06-18 12:48:02
Hey, whenever I try //gs org it just says that all items are found, but it doesn't do anything?
I've added the line to my lua file.
Here's my debug file.
Organizer loaded at 06/18/15 08:10:45
2015-06-18 08:10:45| Organizer [VERBOSE] Adding inventory to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding satchel to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding sack to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding safe to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding wardrobe to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding storage to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding locker to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding safe2 to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding case to the pull list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding inventory to the push list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding locker to the push list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding sack to the push list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding storage to the push list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding wardrobe to the push list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding satchel to the push list
2015-06-18 08:10:45| Organizer [VERBOSE] Adding safe to the push list
2015-06-18 08:10:46| Organizer [VERBOSE] Adding case to the push list
2015-06-18 08:10:46| Organizer [VERBOSE] Adding safe2 to the push list
2015-06-18 08:10:56| Organizer [MSG] Starting...
2015-06-18 08:10:56| Organizer [VERBOSE] Getting!
2015-06-18 08:10:56| Organizer [VERBOSE] Got 0 item(s), and failed getting 0 item(s)
2015-06-18 08:10:56| Organizer [VERBOSE] No remainder, so we found everything we were looking for!
2015-06-18 08:10:56| Organizer [MSG] Done! - 0 items matched and 0 items missing!
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-18 12:52:41
What does //gs validate say? It's indicating that it didn't have anything to find.
Asura.Finbar
サーバ: Asura
Game: FFXI
Posts: 86
By Asura.Finbar 2015-06-18 15:04:31
I figured it wasn't a bug with Organizer, but wanted to bring it to your attention all the same. Thanks for the hard work.
By the way, this is probably covered elsewhere, but sometimes I have to //gs org a few times to grab the last items. As an example, I might get 63 items found and 1 missing, so I type in //gs org once or twice more and eventually I'll get 64 items found and 0 missing. Is this normal behavior or is something wrong on my end?
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-18 15:11:38
I figured it wasn't a bug with Organizer, but wanted to bring it to your attention all the same. Thanks for the hard work.
By the way, this is probably covered elsewhere, but sometimes I have to //gs org a few times to grab the last items. As an example, I might get 63 items found and 1 missing, so I type in //gs org once or twice more and eventually I'll get 64 items found and 0 missing. Is this normal behavior or is something wrong on my end?
Normal (well, expected) behavior. Organizer only makes two passes over your inventory to try and straighten things out, to avoid infinite looping in cases where it can't figure out the right answer (low on space is the big reason for that). There isn't really a good answer for that; I can't let it spin endlessly. The best I can do is report that I didn't find everything. (In the case of //gs org, I could call //gs validate after, but I assumed people were doing that anyway.)
サーバ: Asura
Game: FFXI
Posts: 59
By Asura.Orangebear 2015-06-18 17:16:10
What does //gs validate say? It's indicating that it didn't have anything to find.
It lists all of the equipment pieces, and then finishes with "GearSwap: Final count = 63"
Lakshmi.Rooks
Administrator
サーバ: Lakshmi
Game: FFXI
Posts: 1566
By Lakshmi.Rooks 2015-06-18 17:58:32
What does //gs validate say? It's indicating that it didn't have anything to find.
It lists all of the equipment pieces, and then finishes with "GearSwap: Final count = 63"
It lists missing pieces? Are those pieces in your inventories somewhere and organizer is failing to get them? I don't really have enough information to go on.
サーバ: Asura
Game: FFXI
Posts: 59
By Asura.Orangebear 2015-06-19 01:58:06
What does //gs validate say? It's indicating that it didn't have anything to find.
It lists all of the equipment pieces, and then finishes with "GearSwap: Final count = 63"
It lists missing pieces? Are those pieces in your inventories somewhere and organizer is failing to get them? I don't really have enough information to go on.
Sorry... when I type //gs validate, it shows me all of the equipment pieces in the lua that isn't currently in my inventory, then gives the message "GearSwap: Final count = 63".
When I type //gs org, it says straight away "Done! - 0 items matched and 0 items missing!"
I have entered the line " include('organizer-lib')" at the very start of my lua file on the selected jobs.
I tried doing this on different jobs, but I get the same error message. My inventory doesn't actually get changed at all, no items are moved. I tried this from within my mog house in my starter city.
One thing I have noticed, is that I have a file created named "organizer-lib-file.lua" only in "Wardrobe" and "Inventory", even though the items within my gearswap are scattered around other areas of my mog house.
My inventory isn't full.
Settings.xml File <?xml version="1.1" ?>
<settings>
<global>
<auto_heal>false</auto_heal>
<bag_priority>
<Case>7</Case>
<Inventory>8</Inventory>
<Locker>3</Locker>
<Sack>6</Sack>
<Safe>1</Safe>
<Safe2>2</Safe2>
<Satchel>5</Satchel>
<Storage>4</Storage>
<Wardrobe>9</Wardrobe>
</bag_priority>
<default_file>default.lua</default_file>
<dump_bags>
<Case>7</Case>
<Inventory>8</Inventory>
<Locker>3</Locker>
<Sack>6</Sack>
<Safe>1</Safe>
<Safe2>2</Safe2>
<Satchel>5</Satchel>
<Storage>4</Storage>
<Wardrobe>9</Wardrobe>
</dump_bags>
<ignore>
</ignore>
<item_delay>0</item_delay>
<retain>
<moogle_slip_gear>false</moogle_slip_gear>
<seals>false</seals>
</retain>
<verbose>false</verbose>
</global>
</settings>
organizer.lua --Copyright (c) 2015, Byrthnoth and Rooks
--All rights reserved.
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are met:
-- * Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
-- * Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
-- * Neither the name of <addon name> nor the
-- names of its contributors may be used to endorse or promote products
-- derived from this software without specific prior written permission.
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
--ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
--WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
--DISCLAIMED. IN NO EVENT SHALL <your name> BE LIABLE FOR ANY
--DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
--(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
--LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
--ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
--(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
res = require 'resources'
files = require 'files'
require 'pack'
Items = require 'items'
extdata = require 'extdata'
logger = require 'logger'
require 'tables'
require 'lists'
require 'functions'
config = require 'config'
_addon.name = 'Organizer'
_addon.author = 'Byrth, maintainer: Rooks'
_addon.version = 0.20150531
_addon.commands = {'organizer','org'}
_static = {
bag_ids = {
inventory=0,
safe=1,
storage=2,
temporary=3,
locker=4,
satchel=5,
sack=6,
case=7,
wardrobe=8,
safe2=9
}
}
_global = {
language = 'english',
language_log = 'english_log',
}
_ignore_list = {}
_retain = {}
_valid_pull = {}
_valid_dump = {}
default_settings = {
dump_bags = {['Safe']=1,['Safe2']=2,['Locker']=3,['Storage']=4,['Satchel']=5,['Sack']=6,['Case']=7,['Inventory']=8,['Wardrobe']=9},
bag_priority = {['Safe']=1,['Safe2']=2,['Locker']=3,['Storage']=4,['Satchel']=5,['Sack']=6,['Case']=7,['Inventory']=8,['Wardrobe']=9},
item_delay = 0,
ignore = {},
retain = {
["moogle_slip_gear"]=false,
["seals"]=false
},
auto_heal = false,
default_file='default.lua',
verbose=false,
}
_debugging = {
debug = {
['contains']=true,
['command']=true,
['find']=true,
['find_all']=true,
['items']=true,
['move']=true,
['settings']=true,
['stacks']=true
},
debug_log = 'data\\organizer-debug.log',
enabled = false,
warnings = false, -- This mode gives warnings about impossible item movements and crash conditions.
}
debug_log = files.new(_debugging.debug_log)
function s_to_bag(str)
if not str and tostring(str) then return end
for i,v in pairs(res.bags) do
if v.en:lower():gsub(' ', '') == str:lower() then
return v.id
end
end
end
windower.register_event('load',function()
debug_log:write('Organizer loaded at '..os.date()..'\n')
if debugging then windower.debug('load') end
options_load()
end)
function options_load( )
if not windower.dir_exists(windower.addon_path..'data\\') then
org_debug("settings", "Creating data directory")
windower.create_dir(windower.addon_path..'data\\')
if not windower.dir_exists(windower.addon_path..'data\\') then
org_error("unable to create data directory!")
end
end
for bag_name, bag_id in pairs(_static.bag_ids) do
if not windower.dir_exists(windower.addon_path..'data\\'..bag_name) then
org_debug("settings", "Creating data directory for "..bag_name)
windower.create_dir(windower.addon_path..'data\\'..bag_name)
if not windower.dir_exists(windower.addon_path..'data\\'..bag_name) then
org_error("unable to create"..bag_name.."directory!")
end
end
end
-- We can't just do a:
--
-- settings = config.load('data\\settings.xml', default_settings)
--
-- because the config library will try to merge them, and it will
-- add back anything a user has removed (like items in bag_priority)
if windower.file_exists(windower.addon_path..'data\\settings.xml') then
org_debug("settings", "Loading settings from file")
settings = config.load('data\\settings.xml')
else
org_debug("settings", "Saving default settings to file")
settings = config.load('data\\settings.xml', default_settings)
end
-- Build the ignore list
if(settings.ignore) then
for bn,i_list in pairs(settings.ignore) do
bag_name = bn:lower()
_ignore_list[bag_name] = {}
for _,ignore_name in pairs(i_list) do
org_verbose("Adding "..ignore_name.." in the "..bag_name.." to the ignore list")
_ignore_list[bag_name][ignore_name] = 1
end
end
end
-- Build a hard-wired pull list
for bag_name,_ in pairs(settings.bag_priority) do
org_verbose("Adding "..bag_name.." to the pull list")
_valid_pull[s_to_bag(bag_name)] = 1
end
-- Build a hard-wired dump list
for bag_name,_ in pairs(settings.dump_bags) do
org_verbose("Adding "..bag_name.." to the push list")
_valid_dump[s_to_bag(bag_name)] = 1
end
-- Build the retain lists
if(settings.retain) then
if(settings.retain.moogle_slip_gear == true) then
slip_lists = require('slips')
for slip_id,slip_list in pairs(slip_lists.items) do
for item_id in slip_list:it() do
_retain[item_id] = "moogle slip"
org_debug("settings", "Adding ("..res.items[item_id].english..') to slip retain list')
end
end
end
if(settings.retain.seals == true) then
seals = {1126,1127,2955,2956,2957}
for _,seal_id in pairs(seals) do
_retain[seal_id] = "seal"
org_debug("settings", "Adding ("..res.items[seal_id].english..') to slip retain list')
end
end
end
-- Always allow inventory and wardrobe, obviously
_valid_dump[0] = 1
_valid_pull[0] = 1
_valid_dump[8] = 1
_valid_pull[8] = 1
end
windower.register_event('addon command',function(...)
local inp = {...}
-- get (g) = Take the passed file and move everything to its defined location.
-- tidy (t) = Take the passed file and move everything that isn't in it out of my active inventory.
-- organize (o) = get followed by tidy.
local command = table.remove(inp,1):lower()
if command == 'eval' then
assert(loadstring(table.concat(inp,' ')))()
return
end
local bag = 'all'
if inp[1] and (_static.bag_ids[inp[1]:lower()] or inp[1]:lower() == 'all') then
bag = table.remove(inp,1):lower()
end
org_debug("command", "Using '"..bag.."' as the bag target")
file_name = table.concat(inp,' ')
if string.length(file_name) == 0 then
file_name = default_file_name()
end
if file_name:sub(-4) ~= '.lua' then
file_name = file_name..'.lua'
end
org_debug("command", "Using '"..file_name.."' as the file name")
if (command == 'g' or command == 'get') then
org_debug("command", "Calling get with file_name '"..file_name.."' and bag '"..bag.."'")
get(thaw(file_name, bag))
elseif (command == 't' or command == 'tidy') then
org_debug("command", "Calling tidy with file_name '"..file_name.."' and bag '"..bag.."'")
tidy(thaw(file_name, bag))
elseif (command == 'f' or command == 'freeze') then
org_debug("command", "Calling freeze command")
local items = Items.new(windower.ffxi.get_items(),true)
local frozen = {}
items[3] = nil -- Don't export temporary items
if _static.bag_ids[bag] then
org_debug("command", "Bag: "..bag)
freeze(file_name,bag,items)
else
for bag_id,item_list in items:it() do
org_debug("command", "Bag ID: "..bag_id)
-- infinite loop protection
if(frozen[bag_id]) then
org_warning("Tried to freeze ID #"..bag_id.." twice, aborting")
return
end
frozen[bag_id] = 1
freeze(file_name,res.bags[bag_id].english:lower():gsub(' ', ''),items)
end
end
elseif (command == 'o' or command == 'organize') then
org_debug("command", "Calling organize command")
organize(thaw(file_name, bag))
end
if settings.auto_heal and tostring(settings.auto_heal):lower() ~= 'false' then
org_debug("command", "Automatically healing")
windower.send_command('input /heal')
end
org_debug("command", "Organizer complete")
end)
function get(goal_items,current_items)
org_verbose('Getting!')
if goal_items then
count = 0
failed = 0
current_items = current_items or Items.new()
goal_items, current_items = clean_goal(goal_items,current_items)
for bag_id,inv in goal_items:it() do
for ind,item in inv:it() do
if not item:annihilated() then
local start_bag, start_ind = current_items:find(item)
-- Table contains a list of {bag, pos, count}
if start_bag then
if not current_items:route(start_bag,start_ind,bag_id) then
org_warning('Unable to move item.')
failed = failed + 1
else
count = count + 1
end
simulate_item_delay()
else
-- Need to adapt this for stacking items somehow.
org_warning(res.items[item.id].english..' not found.')
end
end
end
end
org_verbose("Got "..count.." item(s), and failed getting "..failed.." item(s)")
end
return goal_items, current_items
end
function freeze(file_name,bag,items)
org_debug("command", "Entering freeze function with bag '"..bag.."'")
local lua_export = T{}
local counter = 0
for _,item_table in items[_static.bag_ids[bag]]:it() do
counter = counter + 1
if(counter > 80) then
org_warning("We hit an infinite loop in freeze()! ABORT.")
return
end
org_debug("command", "In freeze loop for bag '"..bag.."'")
org_debug("command", "Processing '"..item_table.log_name.."'")
local temp_ext,augments = extdata.decode(item_table)
if temp_ext.augments then
org_debug("command", "Got augments for '"..item_table.log_name.."'")
augments = table.filter(temp_ext.augments,-functions.equals('none'))
end
lua_export:append({name = item_table.name,log_name=item_table.log_name,
id=item_table.id,extdata=item_table.extdata:hex(),augments = augments,count=item_table.count})
end
-- Make sure we have something in the bag at all
if lua_export[1] then
org_verbose("Freezing "..tostring(bag)..".")
local export_file = files.new('/data/'..bag..'/'..file_name,true)
export_file:write('return '..lua_export:tovstring({'augments','log_name','name','id','count','extdata'}))
else
org_debug("command", "Got nothing, skipping '"..bag.."'")
end
end
function tidy(goal_items,current_items,usable_bags)
org_debug("command", "Entering tidy()")
usable_bags = usable_bags or get_dump_bags()
-- Move everything out of items[0] and into other inventories (defined by the passed table)
if goal_items and goal_items[0] and goal_items[0]._info.n > 0 then
current_items = current_items or Items.new()
goal_items, current_items = clean_goal(goal_items,current_items)
for index,item in current_items[0]:it() do
if not goal_items[0]:contains(item,true) then
org_debug("command", "Putting away "..item.log_name)
current_items[0][index]:put_away(usable_bags)
simulate_item_delay()
end
end
end
return goal_items, current_items
end
function organize(goal_items)
org_message('Starting...')
local current_items = Items.new()
local dump_bags = get_dump_bags()
local inventory_max = windower.ffxi.get_bag_info(0).max
if current_items[0].n == inventory_max then
tidy(goal_items,current_items,dump_bags)
end
if current_items[0].n == inventory_max then
org_error('Unable to make space, aborting!')
return
end
local remainder = math.huge
while remainder do
goal_items, current_items = get(goal_items,current_items)
goal_items, current_items = clean_goal(goal_items,current_items)
goal_items, current_items = tidy(goal_items,current_items,dump_bags)
remainder = incompletion_check(goal_items,remainder)
if(remainder) then
org_verbose("Remainder: "..tostring(remainder)..' Current: '..current_items[0]._info.n,1)
else
org_verbose("No remainder, so we found everything we were looking for!")
end
end
goal_items, current_items = tidy(goal_items,current_items,dump_bags)
local count,failures = 0,T{}
for bag_id,bag in goal_items:it() do
for ind,item in bag:it() do
if item:annihilated() then
count = count + 1
else
item.bag_id = bag_id
failures:append(item)
end
end
end
org_message('Done! - '..count..' items matched and '..table.length(failures)..' items missing!')
if table.length(failures) > 0 then
for i,v in failures:it() do
org_verbose('Item Missing: '..i.name..' '..(i.augments and tostring(T(i.augments)) or ''))
end
end
end
function clean_goal(goal_items,current_items)
for i,inv in goal_items:it() do
for ind,item in inv:it() do
local potential_ind = current_items:contains(item)
if potential_ind then
-- If it is already in the right spot, delete it from the goal items and annihilate it.
local count = math.min(goal_items[ind].count,current_items[potential_ind].count)
goal_items[ind]:annihilate(goal_items[ind].count)
current_items[potential_ind]:annihilate(current_items[potential_ind].count)
end
end
end
return goal_items, current_items
end
function incompletion_check(goal_items,remainder)
-- Does not work. On cycle 1, you fill up your inventory without purging unnecessary stuff out.
-- On cycle 2, your inventory is full. A gentler version of tidy needs to be in the loop somehow.
local remaining = 0
for i,v in goal_items:it() do
for n,m in v:it() do
if not m:annihilated() then
remaining = remaining + 1
end
end
end
return remaining ~= 0 and remaining < remainder and remaining
end
function thaw(file_name,bag)
local bags = _static.bag_ids[bag] and {[bag]=file_name} or table.reassign({},_static.bag_ids) -- One bag name or all of them if no bag is specified
if settings.default_file:sub(-4) ~= '.lua' then
settings.default_file = settings.default_file..'.lua'
end
for i,v in pairs(_static.bag_ids) do
bags = bags and windower.file_exists(windower.addon_path..'data/'..i..'/'..file_name) and file_name or default_file_name()
end
bags.temporary = nil
local inv_structure = {}
for cur_bag,file in pairs(bags) do
local f,err = loadfile(windower.addon_path..'data/'..cur_bag..'/'..file)
if f and not err then
local success = false
success, inv_structure[cur_bag] = pcall(f)
if not success then
org_warning('User File Error (Syntax) - '..inv_structure[cur_bag])
inv_structure[cur_bag] = nil
end
elseif bag and cur_bag:lower() == bag:lower() then
org_warning('User File Error (Loading) - '..err)
end
end
-- Convert all the extdata back to a normal string
for i,v in pairs(inv_structure) do
for n,m in pairs(v) do
if m.extdata then
inv_structure[n].extdata = string.parse_hex(m.extdata)
end
end
end
return Items.new(inv_structure)
end
function org_message(msg,col)
windower.add_to_chat(col or 8,'Organizer: '..msg)
flog(_debugging.debug_log, 'Organizer [MSG] '..msg)
end
function org_warning(msg)
if _debugging.warnings then
windower.add_to_chat(123,'Organizer: '..msg)
end
flog(_debugging.debug_log, 'Organizer [WARN] '..msg)
end
function org_debug(level, msg)
if(_debugging.enabled) then
if (_debugging.debug[level]) then
flog(_debugging.debug_log, 'Organizer [DEBUG] ['..level..']: '..msg)
end
end
end
function org_error(msg)
error('Organizer: '..msg)
flog(_debugging.debug_log, 'Organizer [ERROR] '..msg)
end
function org_verbose(msg,col)
if tostring(settings.verbose):lower() ~= 'false' then
windower.add_to_chat(col or 8,'Organizer: '..msg)
end
flog(_debugging.debug_log, 'Organizer [VERBOSE] '..msg)
end
function default_file_name()
player = windower.ffxi.get_player()
job_name = res.jobs[player.main_job_id]['english_short']
return player.name..'_'..job_name..'.lua'
end
function simulate_item_delay()
if settings.item_delay and settings.item_delay > 0 then
coroutine.sleep(settings.item_delay)
end
end
function get_dump_bags()
local dump_bags = {}
for i,v in pairs(settings.dump_bags) do
if i and s_to_bag(i) then
dump_bags[tonumber(v)] = s_to_bag(i)
elseif i then
org_error('The bag name ("'..tostring(i)..'") in dump_bags entry #'..tostring(v)..' in the ../addons/organizer/data/settings.xml file is not valid.\nValid options are '..tostring(res.bags))
return
end
end
return dump_bags
end
Running Windows 8, Windower 4, EU FFXI.
Here is a copy of the gearswap that I've tried include('organizer-lib')
-------------------------------------------------------------------------------------------------------------------
-- Setup functions for this job. Generally should not be modified.
-------------------------------------------------------------------------------------------------------------------
--[[
Custom commands:
ExtraSongsMode may take one of three values: None, Dummy, FullLength
You can set these via the standard 'set' and 'cycle' self-commands. EG:
gs c cycle ExtraSongsMode
gs c set ExtraSongsMode Dummy
The Dummy state will equip the bonus song instrument and ensure non-duration gear is equipped.
The FullLength state will simply equip the bonus song instrument on top of standard gear.
Simple macro to cast a dummy Daurdabla song:
/console gs c set ExtraSongsMode Dummy
/ma "Shining Fantasia" <me>
To use a Terpander rather than Daurdabla, set the info.ExtraSongInstrument variable to
'Terpander', and info.ExtraSongs to 1.
--]]
-- Initialization function for this job file.
function get_sets()
mote_include_version = 2
-- Load and initialize the include file.
include('Mote-Include.lua')
end
-- Setup vars that are user-independent. state.Buff vars initialized here will automatically be tracked.
function job_setup()
state.ExtraSongsMode = M{['description']='Extra Songs', 'None', 'Dummy', 'FullLength'}
state.Buff['Pianissimo'] = buffactive['pianissimo'] or false
-- For tracking current recast timers via the Timers plugin.
custom_timers = {}
end
-------------------------------------------------------------------------------------------------------------------
-- User setup functions for this job. Recommend that these be overridden in a sidecar file.
-------------------------------------------------------------------------------------------------------------------
-- Setup vars that are user-dependent. Can override this function in a sidecar file.
function user_setup()
state.OffenseMode:options('None', 'Normal')
state.CastingMode:options('Normal', 'Resistant')
state.IdleMode:options('Normal', 'PDT')
brd_daggers = S{'Izhiikoh','Atoyac'}
pick_tp_weapon()
-- Adjust this if using the Terpander (new +song instrument)
info.ExtraSongInstrument = 'Daurdabla'
-- How many extra songs we can keep from Daurdabla/Terpander
info.ExtraSongs = 1
-- Set this to false if you don't want to use custom timers.
state.UseCustomTimers = M(true, 'Use Custom Timers')
-- Additional local binds
send_command('bind ^` gs c cycle ExtraSongsMode')
send_command('bind !` input /ma "Chocobo Mazurka" <me>')
select_default_macro_book()
end
-- Called when this job file is unloaded (eg: job change)
function user_unload()
send_command('unbind ^`')
send_command('unbind !`')
end
-- Define sets and vars used by this job file.
function init_gear_sets()
--------------------------------------
-- Start defining the sets
--------------------------------------
-- Precast Sets
-- Fast cast sets for spells
sets.precast.FC = {head="Nahtirah Hat",ear2="Loquac. Earring",
hands="Gendewitha Gages +1",ring1="Prolix Ring",
back="Swith Cape +1",waist="Witful Belt",legs="Artsieq Hose",feet="Chelona Boots"}
sets.precast.FC.Cure = set_combine(sets.precast.FC, {body="Heka's Kalasiris"})
sets.precast.FC.Stoneskin = set_combine(sets.precast.FC, {head="Umuthi Hat"})
sets.precast.FC['Enhancing Magic'] = set_combine(sets.precast.FC, {waist="Siegel Sash"})
sets.precast.FC.BardSong = {main="Felibre's Dague",range="Gjallarhorn",
head="Aoidos' Calot +2",neck="Aoidos' Matinee",ear1="Aoidos' Earring",ear2="Loquac. Earring",
body="Sha'ir Manteel",hands="Gendewitha Gages +1",ring1="Prolix Ring",
back="Swith Cape +1",waist="Witful Belt",legs="Gendewitha Spats +1",feet="Bihu Slippers"}
sets.precast.FC.Daurdabla = set_combine(sets.precast.FC.BardSong, {range=info.ExtraSongInstrument})
-- Precast sets to enhance JAs
sets.precast.JA.Nightingale = {feet="Bihu Slippers"}
sets.precast.JA.Troubadour = {body="Bihu Justaucorps"}
sets.precast.JA['Soul Voice'] = {legs="Bihu Cannions"}
-- Waltz set (chr and vit)
sets.precast.Waltz = {range="Gjallarhorn",
head="Nahtirah Hat",
body="Gende. Bilaut +1",hands="Buremte Gloves",
back="Kumbira Cape",legs="Gendewitha Spats +1",feet="Gendewitha Galoshes +1"}
-- Weaponskill sets
-- Default set for any weaponskill that isn't any more specifically defined
sets.precast.WS = {range="Gjallarhorn",
head="Nahtirah Hat",neck=gear.ElementalGorget,ear1="Bladeborn Earring",ear2="Steelflash Earring",
body="Bihu Justaucorps",hands="Buremte Gloves",ring1="Rajas Ring",ring2="K'ayres Ring",
back="Atheling Mantle",waist="Caudata Belt",legs="Brioso Cannions +1",feet="Gendewitha Galoshes +1"}
-- Specific weaponskill sets. Uses the base set if an appropriate WSMod version isn't found.
sets.precast.WS['Evisceration'] = set_combine(sets.precast.WS)
sets.precast.WS['Exenterator'] = set_combine(sets.precast.WS)
sets.precast.WS['Mordant Rime'] = set_combine(sets.precast.WS)
-- Midcast Sets
-- General set for recast times.
sets.midcast.FastRecast = {range="Angel Lyre",
head="Nahtirah Hat",ear2="Loquacious Earring",
body="Vanir Cotehardie",hands="Gendewitha Gages +1",ring1="Prolix Ring",
back="Swith Cape +1",waist="Goading Belt",legs="Gendewitha Spats +1",feet="Gendewitha Galoshes +1"}
-- Gear to enhance certain classes of songs. No instruments added here since Gjallarhorn is being used.
sets.midcast.Ballad = {legs="Aoidos' Rhing. +2"}
sets.midcast.Lullaby = {hands=""}
sets.midcast.Madrigal = {head="Aoidos' Calot +2"}
sets.midcast.March = {hands="Aoidos' Manchettes +2"}
sets.midcast.Minuet = {body="Aoidos' Hongreline +2"}
sets.midcast.Minne = {}
sets.midcast.Paeon = {head=""}
sets.midcast.Carol = {head="Aoidos' Calot +2",
body="Aoidos' Hongreline +2",hands="Aoidos' Manchettes +2",
legs="Aoidos' Rhing. +2",feet="Aoidos' Cothrn. +2"}
sets.midcast["Sentinel's Scherzo"] = {feet="Aoidos' Cothrn. +2"}
sets.midcast['Magic Finale'] = {legs="Aoidos' Rhing. +2"}
sets.midcast.Mazurka = {range=info.ExtraSongInstrument}
-- For song buffs (duration and AF3 set bonus)
sets.midcast.SongEffect = {main="Legato Dagger",range="Gjallarhorn",
head="Aoidos' Calot +2",neck="Aoidos' Matinee",ear2="Loquacious Earring",
body="Aoidos' Hongreline +2",hands="Aoidos' Manchettes +2",ring1="Prolix Ring",
legs="Marduk's Shalwar +1",feet="Brioso Slippers +1"}
-- For song defbuffs (duration primary, accuracy secondary)
sets.midcast.SongDebuff = {main="Lehbrailg +2",sub="Mephitis Grip",range="Gjallarhorn",
head="Bihu Roundlet +1",neck="Aoidos' Matinee",ear1="Psystorm Earring",ear2="Lifestorm Earring",
body="Aoidos' Hongreline +2",hands="Aoidos' Manchettes +2",ring1="Prolix Ring",ring2="Sangoma Ring",
back="Kumbira Cape",waist="Goading Belt",legs="Marduk's Shalwar +1",feet="Brioso Slippers +1"}
-- For song defbuffs (accuracy primary, duration secondary)
sets.midcast.ResistantSongDebuff = {main="Lehbrailg +2",sub="Mephitis Grip",range="Gjallarhorn",
head="Bihu Roundlet +1",neck="Piper's Torque",ear1="Psystorm Earring",ear2="Lifestorm Earring",
body="Brioso Justaucorps +1",hands="Aoidos' Manchettes +2",ring1="Prolix Ring",ring2="Sangoma Ring",
back="Kumbira Cape",waist="Demonry Sash",legs="Brioso Cannions +1",feet="Artsieq Boots"}
-- Song-specific recast reduction
sets.midcast.SongRecast = {ear2="Loquacious Earring",
ring1="Prolix Ring",
back="Swith Cape +1",legs="Aoidos' Rhing. +2"}
--sets.midcast.Daurdabla = set_combine(sets.midcast.FastRecast, sets.midcast.SongRecast, {range=info.ExtraSongInstrument})
-- Cast spell with normal gear, except using Daurdabla instead
sets.midcast.Daurdabla = {range=info.ExtraSongInstrument}
-- Dummy song with Daurdabla; minimize duration to make it easy to overwrite.
sets.midcast.DaurdablaDummy = {main="Izhiikoh",range=info.ExtraSongInstrument,
head="Nahtirah Hat",neck="Piper's Torque",ear1="Psystorm Earring",ear2="Lifestorm Earring",
body="Brioso Justaucorps +1",hands="Aoidos' Manchettes +2",ring1="Prolix Ring",ring2="Sangoma Ring",
back="Swith Cape +1",waist="Goading Belt",legs="Gendewitha Spats +1",feet="Artsieq Boots"}
-- Other general spells and classes.
sets.midcast.Cure = {main="Chatoyant Staff",sub='Oneiros Grip',
head="Gende. Caubeen +1",
body="Gende. Bilaut +1",hands="Bokwus Gloves",ring1="Ephedra Ring",ring2="Sirona's Ring",
legs="Gendewitha Spats +1",feet="Gendewitha Galoshes +1"}
sets.midcast.Curaga = sets.midcast.Cure
sets.midcast.Stoneskin = {
head="Nahtirah Hat",
body="Gende. Bilaut +1",hands="Gendewitha Gages +1",
legs="Gendewitha Spats +1",feet="Gendewitha Galoshes +1"}
sets.midcast.Cursna = {
ring1="Ephedra Ring"}
-- Sets to return to when not performing an action.
-- Resting sets
sets.resting = {main="Chatoyant Staff",
body="Gende. Bilaut +1",hands="Serpentes Cuffs",
legs="Nares Trews",feet="Serpentes Sabots"}
-- Idle sets (default idle set not needed since the other three are defined, but leaving for testing purposes)
sets.idle = {main="Terra's Staff", sub="Oneiros Grip",range="Oneiros Harp",
head="Wivre Hairpin",neck="Wiglen Gorget",ear1="Bloodgem Earring",ear2="Loquacious Earring",
body="Gende. Bilaut +1",hands="Serpentes Cuffs",ring1="Paguroidea Ring",ring2="Sangoma Ring",
back="Kumbira Cape",waist="Flume Belt",legs="Nares Trews",feet="Serpentes Sabots"}
sets.idle.PDT = {main="Terra's Staff", sub="Oneiros Grip",range="Oneiros Harp",
head="Gende. Caubeen +1",neck="Wiglen Gorget",ear1="Bloodgem Earring",ear2="Loquacious Earring",
body="Gende. Bilaut +1",hands="Gendewitha Gages +1",ring1="Dark Ring",ring2="Sangoma Ring",
back="Kumbira Cape",waist="Flume Belt",legs="Gendewitha Spats +1",feet="Serpentes Sabots"}
sets.idle.Town = {main="Lehbrailg +2", sub="Oneiros Grip",range="Gjallarhorn",
head="Bihu Roundlet +1",neck="Piper's Torque",ear1="Aoidos' Earring",ear2="Loquacious Earring",
body="Bihu Justaucorps",hands="Gendewitha Gages +1",ring1="Paguroidea Ring",ring2="Sangoma Ring",
back="Kumbira Cape",waist="Flume Belt",legs="Mdk. Shalwar +1",feet="Aoidos' Cothurnes +2"}
sets.idle.Weak = {main="Terra's Staff",sub="Oneiros Grip",range="Oneiros Harp",
head="Gende. Caubeen +1",neck="Twilight Torque",ear1="Bloodgem Earring",
body="Gende. Bilaut +1",hands="Gendewitha Gages +1",ring1="Dark Ring",ring2="Sangoma Ring",
back="Kumbira Cape",waist="Flume Belt",legs="Gendewitha Spats +1",feet="Serpentes Sabots"}
-- Defense sets
sets.defense.PDT = {main="Terra's Staff",sub="Oneiros Grip",
head="Gende. Caubeen +1",neck="Twilight Torque",
body="Gende. Bilaut +1",hands="Gendewitha Gages +1",ring1="Dark Ring",ring2="Dark Ring",
back="Kumbira Cape",waist="Flume Belt",legs="Gendewitha Spats +1",feet="Gendewitha Galoshes +1"}
sets.defense.MDT = {main="Terra's Staff",sub="Oneiros Grip",
head="Nahtirah Hat",neck="Twilight Torque",
body="Gende. Bilaut +1",hands="Gendewitha Gages +1",ring1="Dark Ring",ring2="Shadow Ring",
back="Repulse Mantle",waist="Flume Belt",legs="Bihu Cannions",feet="Gendewitha Galoshes +1"}
sets.Kiting = {feet="Aoidos' Cothurnes +2"}
sets.latent_refresh = {waist="Fucho-no-obi"}
-- Engaged sets
-- Variations for TP weapon and (optional) offense/defense modes. Code will fall back on previous
-- sets if more refined versions aren't defined.
-- If you create a set with both offense and defense modes, the offense mode should be first.
-- EG: sets.engaged.Dagger.Accuracy.Evasion
-- Basic set for if no TP weapon is defined.
sets.engaged = {range="Angel Lyre",
head="Nahtirah Hat",neck="Asperity Necklace",ear1="Bladeborn Earring",ear2="Steelflash Earring",
body="Bihu Justaucorps",hands="Buremte Gloves",ring1="Rajas Ring",ring2="K'ayres Ring",
back="Atheling Mantle",waist="Goading Belt",legs="Brioso Cannions +1",feet="Gendewitha Galoshes +1"}
-- Sets with weapons defined.
sets.engaged.Dagger = {range="Angel Lyre",
head="Nahtirah Hat",neck="Asperity Necklace",ear1="Bladeborn Earring",ear2="Steelflash Earring",
body="Bihu Justaucorps",hands="Buremte Gloves",ring1="Rajas Ring",ring2="K'ayres Ring",
back="Atheling Mantle",waist="Goading Belt",legs="Brioso Cannions +1",feet="Gendewitha Galoshes +1"}
-- Set if dual-wielding
sets.engaged.DW = {range="Angel Lyre",
head="Nahtirah Hat",neck="Asperity Necklace",ear1="Dudgeon Earring",ear2="Heartseeker Earring",
body="Bihu Justaucorps",hands="Buremte Gloves",ring1="Rajas Ring",ring2="K'ayres Ring",
back="Atheling Mantle",waist="Goading Belt",legs="Brioso Cannions +1",feet="Gendewitha Galoshes +1"}
end
-------------------------------------------------------------------------------------------------------------------
-- Job-specific hooks for standard casting events.
-------------------------------------------------------------------------------------------------------------------
-- Set eventArgs.handled to true if we don't want any automatic gear equipping to be done.
-- Set eventArgs.useMidcastGear to true if we want midcast gear equipped on precast.
function job_precast(spell, action, spellMap, eventArgs)
if spell.type == 'BardSong' then
-- Auto-Pianissimo
if ((spell.target.type == 'PLAYER' and not spell.target.charmed) or (spell.target.type == 'NPC' and spell.target.in_party)) and
not state.Buff['Pianissimo'] then
local spell_recasts = windower.ffxi.get_spell_recasts()
if spell_recasts[spell.recast_id] < 2 then
send_command('@input /ja "Pianissimo" <me>; wait 1.5; input /ma "'..spell.name..'" '..spell.target.name)
eventArgs.cancel = true
return
end
end
end
end
-- Set eventArgs.handled to true if we don't want any automatic gear equipping to be done.
function job_midcast(spell, action, spellMap, eventArgs)
if spell.action_type == 'Magic' then
if spell.type == 'BardSong' then
-- layer general gear on first, then let default handler add song-specific gear.
local generalClass = get_song_class(spell)
if generalClass and sets.midcast[generalClass] then
equip(sets.midcast[generalClass])
end
end
end
end
function job_post_midcast(spell, action, spellMap, eventArgs)
if spell.type == 'BardSong' then
if state.ExtraSongsMode.value == 'FullLength' then
equip(sets.midcast.Daurdabla)
end
state.ExtraSongsMode:reset()
end
end
-- Set eventArgs.handled to true if we don't want automatic gear equipping to be done.
function job_aftercast(spell, action, spellMap, eventArgs)
if spell.type == 'BardSong' and not spell.interrupted then
if spell.target and spell.target.type == 'SELF' then
adjust_timers(spell, spellMap)
end
end
end
-------------------------------------------------------------------------------------------------------------------
-- Job-specific hooks for non-casting events.
-------------------------------------------------------------------------------------------------------------------
-- Handle notifications of general user state change.
function job_state_change(stateField, newValue, oldValue)
if stateField == 'Offense Mode' then
if newValue == 'Normal' then
disable('main','sub','ammo')
else
enable('main','sub','ammo')
end
end
end
-------------------------------------------------------------------------------------------------------------------
-- User code that supplements standard library decisions.
-------------------------------------------------------------------------------------------------------------------
-- Called by the 'update' self-command.
function job_update(cmdParams, eventArgs)
pick_tp_weapon()
end
-- Modify the default idle set after it was constructed.
function customize_idle_set(idleSet)
if player.mpp < 51 then
idleSet = set_combine(idleSet, sets.latent_refresh)
end
return idleSet
end
-- Function to display the current relevant user state when doing an update.
function display_current_job_state(eventArgs)
display_current_caster_state()
eventArgs.handled = true
end
-------------------------------------------------------------------------------------------------------------------
-- Utility functions specific to this job.
-------------------------------------------------------------------------------------------------------------------
-- Determine the custom class to use for the given song.
function get_song_class(spell)
-- Can't use spell.targets:contains() because this is being pulled from resources
if set.contains(spell.targets, 'Enemy') then
if state.CastingMode == 'Resistant' then
return 'ResistantSongDebuff'
else
return 'SongDebuff'
end
elseif state.ExtraSongsMode.value == 'Dummy' then
return 'DaurdablaDummy'
else
return 'SongEffect'
end
end
-- Function to create custom buff-remaining timers with the Timers plugin,
-- keeping only the actual valid songs rather than spamming the default
-- buff remaining timers.
function adjust_timers(spell, spellMap)
if state.UseCustomTimers.value == false then
return
end
local current_time = os.time()
-- custom_timers contains a table of song names, with the os time when they
-- will expire.
-- Eliminate songs that have already expired from our local list.
local temp_timer_list = {}
for song_name,expires in pairs(custom_timers) do
if expires < current_time then
temp_timer_list[song_name] = true
end
end
for song_name,expires in pairs(temp_timer_list) do
custom_timers[song_name] = nil
end
local dur = calculate_duration(spell.name, spellMap)
if custom_timers[spell.name] then
-- Songs always overwrite themselves now, unless the new song has
-- less duration than the old one (ie: old one was NT version, new
-- one has less duration than what's remaining).
-- If new song will outlast the one in our list, replace it.
if custom_timers[spell.name] < (current_time + dur) then
send_command('timers delete "'..spell.name..'"')
custom_timers[spell.name] = current_time + dur
send_command('timers create "'..spell.name..'" '..dur..' down')
end
else
-- Figure out how many songs we can maintain.
local maxsongs = 2
if player.equipment.range == info.ExtraSongInstrument then
maxsongs = maxsongs + info.ExtraSongs
end
if buffactive['Clarion Call'] then
maxsongs = maxsongs + 1
end
-- If we have more songs active than is currently apparent, we can still overwrite
-- them while they're active, even if not using appropriate gear bonuses (ie: Daur).
if maxsongs < table.length(custom_timers) then
maxsongs = table.length(custom_timers)
end
-- Create or update new song timers.
if table.length(custom_timers) < maxsongs then
custom_timers[spell.name] = current_time + dur
send_command('timers create "'..spell.name..'" '..dur..' down')
else
local rep,repsong
for song_name,expires in pairs(custom_timers) do
if current_time + dur > expires then
if not rep or rep > expires then
rep = expires
repsong = song_name
end
end
end
if repsong then
custom_timers[repsong] = nil
send_command('timers delete "'..repsong..'"')
custom_timers[spell.name] = current_time + dur
send_command('timers create "'..spell.name..'" '..dur..' down')
end
end
end
end
-- Function to calculate the duration of a song based on the equipment used to cast it.
-- Called from adjust_timers(), which is only called on aftercast().
function calculate_duration(spellName, spellMap)
local mult = 1
if player.equipment.range == 'Daurdabla' then mult = mult + 0.25 end -- change to 0.25 with 90 Daur
if player.equipment.range == "Gjallarhorn" then mult = mult + 0.4 end -- change to 0.3 with 95 Gjall
if player.equipment.main == "Carnwenhan" then mult = mult + 0.1 end -- 0.1 for 75, 0.4 for 95, 0.5 for 99/119
if player.equipment.main == "Legato Dagger" then mult = mult + 0.05 end
if player.equipment.sub == "Legato Dagger" then mult = mult + 0.05 end
if player.equipment.neck == "Aoidos' Matinee" then mult = mult + 0.1 end
if player.equipment.body == "Aoidos' Hngrln. +2" then mult = mult + 0.1 end
if player.equipment.legs == "Mdk. Shalwar +1" then mult = mult + 0.1 end
if player.equipment.feet == "Brioso Slippers" then mult = mult + 0.1 end
if player.equipment.feet == "Brioso Slippers +1" then mult = mult + 0.11 end
if spellMap == 'Paeon' and player.equipment.head == "Brioso Roundlet" then mult = mult + 0.1 end
if spellMap == 'Paeon' and player.equipment.head == "Brioso Roundlet +1" then mult = mult + 0.1 end
if spellMap == 'Madrigal' and player.equipment.head == "Aoidos' Calot +2" then mult = mult + 0.1 end
if spellMap == 'Minuet' and player.equipment.body == "Aoidos' Hngrln. +2" then mult = mult + 0.1 end
if spellMap == 'March' and player.equipment.hands == 'Ad. Mnchtte. +2' then mult = mult + 0.1 end
if spellMap == 'Ballad' and player.equipment.legs == "Aoidos' Rhing. +2" then mult = mult + 0.1 end
if spellName == "Sentinel's Scherzo" and player.equipment.feet == "Aoidos' Cothrn. +2" then mult = mult + 0.1 end
if buffactive.Troubadour then
mult = mult*2
end
if spellName == "Sentinel's Scherzo" then
if buffactive['Soul Voice'] then
mult = mult*2
elseif buffactive['Marcato'] then
mult = mult*1.5
end
end
local totalDuration = math.floor(mult*120)
return totalDuration
end
-- Examine equipment to determine what our current TP weapon is.
function pick_tp_weapon()
if brd_daggers:contains(player.equipment.main) then
state.CombatWeapon:set('Dagger')
if S{'NIN','DNC'}:contains(player.sub_job) and brd_daggers:contains(player.equipment.sub) then
state.CombatForm:set('DW')
else
state.CombatForm:reset()
end
else
state.CombatWeapon:reset()
state.CombatForm:reset()
end
end
-- Function to reset timers.
function reset_timers()
for i,v in pairs(custom_timers) do
send_command('timers delete "'..i..'"')
end
custom_timers = {}
end
-- Select default macro book on initial load or subjob change.
function select_default_macro_book()
set_macro_page(1, 13)
end
windower.raw_register_event('zone change',reset_timers)
windower.raw_register_event('logout',reset_timers)
If you need any more info let me know :) thanks for your help! :D
By Rooks 2015-06-19 09:14:07
One thing I have noticed, is that I have a file created named "organizer-lib-file.lua" only in "Wardrobe" and "Inventory", even though the items within my gearswap are scattered around other areas of my mog house.
Organizer uses the .lua files for destinations. //gs org doesn't care where items not in sets end up, only what makes its way to your inventory, so those are the only two files it needs.
Try this for me: in organizer.lua, around line 80, is a structure labeled "_debugging". Set enabled to true, reload organizer, run it again, and then send me the contents of organizer-debug.log from the addons\organizer\data directory.
サーバ: Asura
Game: FFXI
Posts: 59
By Asura.Orangebear 2015-06-19 12:02:32
One thing I have noticed, is that I have a file created named "organizer-lib-file.lua" only in "Wardrobe" and "Inventory", even though the items within my gearswap are scattered around other areas of my mog house.
Organizer uses the .lua files for destinations. //gs org doesn't care where items not in sets end up, only what makes its way to your inventory, so those are the only two files it needs.
Try this for me: in organizer.lua, around line 80, is a structure labeled "_debugging". Set enabled to true, reload organizer, run it again, and then send me the contents of organizer-debug.log from the addons\organizer\data directory.
Hey here it is - I hope I did it right?
Edit: too many characters, I've uploaded it to pastebin
http://pastebin.com/LWNbQ4aA
By Rooks 2015-06-19 12:23:36
Ok, nothing out of the ordinary - can you pastebin the inventory\organizer-lib-file.lua and the output of //gs validate?
サーバ: Asura
Game: FFXI
Posts: 59
By Asura.Orangebear 2015-06-19 20:48:39
Ok, nothing out of the ordinary - can you pastebin the inventory\organizer-lib-file.lua and the output of //gs validate?
Thanks for all your help :)
Here is the lib-file lua, http://pastebin.com/HvQLMbty
GS Validate Pic #1
GS Validate Pic #2
By Rooks 2015-06-19 21:05:10
Ok, so a couple of things don't make any sense.
That generated lib file is clearly for paladin, but it's only get 32 items, and nothing in there is in the //gs validate failure output. That gearswap you showed is for bard, though.
Can you run me through the steps you're doing, exactly? I don't know how you'd even get in this state.
サーバ: Asura
Game: FFXI
Posts: 59
By Asura.Orangebear 2015-06-20 05:01:55
Ok, so a couple of things don't make any sense.
That generated lib file is clearly for paladin, but it's only get 32 items, and nothing in there is in the //gs validate failure output. That gearswap you showed is for bard, though.
Can you run me through the steps you're doing, exactly? I don't know how you'd even get in this state.
Since downloading Organizer, I've added the required line to the top of my PLD and BRD lua files. (I thought maybe it wasn't working on my PLD one, so tried my BRD file).
I tried //gs org on both jobs, but got the same result.
I tried switching jobs, then trying again.
----------------------------------------------------------------
I've just completely deleted the whole organizer folder and redownloaded it again.
Logged into FFXI.
(The required lines are on my PLD & BRD Lua line #1 already)
As soon as I logged in, I was in my mog house on PLD, so I job changed to BRD.
I typed //gs org
//GS ORG result
I then opened organizer.lua and turned on debugg to true
Lua File set to true
I then reloaded Gearswap and Organizer addons, and tried //GS ORG
Pastebin Result of Debug File
Here is the organizer-lib-file.lua from Windower4/Addons/organizer/data/inventory
Pastebin of lib-file-lua
Here is the organizer-lib-file.lua from Windower4/addons/organizer/data/wardrobe
Pastebin of lib-file-lua
Here is the settings file from Windower4/addons/organizer/data
Pastebin of settings file
Here is my BRD gearswap
Pastebin copy of gearswap Lua
And here is my PLD gearswap
Pastebin copy of Gearswap Lua
After all of this, I've just tried to run //org tidy but nothing showed in the chatlog. I looked into the debug file and it had added an extra few lines.
Pastebin of debugg after another //GS tidy
I hope this helps anymore? Not sure if I'm doing something wrong or not, but as far as I can tell I've followed the readme and your instructions to the Tee >_<
Edit: Sorry here are the results of //GS validate
Pic 1
Pic 2
|
|