summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/addons/addons/Rhombus/Rhombus.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Data/BuiltIn/Libraries/addons/addons/Rhombus/Rhombus.lua')
-rw-r--r--Data/BuiltIn/Libraries/addons/addons/Rhombus/Rhombus.lua596
1 files changed, 596 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/addons/addons/Rhombus/Rhombus.lua b/Data/BuiltIn/Libraries/addons/addons/Rhombus/Rhombus.lua
new file mode 100644
index 0000000..1622b43
--- /dev/null
+++ b/Data/BuiltIn/Libraries/addons/addons/Rhombus/Rhombus.lua
@@ -0,0 +1,596 @@
+--[[Copyright © 2014-2015, trv
+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 Rhombus 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 trv 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.--]]
+
+_addon.name = 'Rhombus'
+_addon.author = 'trv'
+_addon.version = '1.2.1'
+
+config = require('config')
+texts = require('texts')
+res = require('resources')
+bit = require('bit')
+require 'tables'
+require('lists')
+require('sets')
+require('logger')
+require('defs')
+require('helper_functions')
+
+config.register(_defaults, function(settings_table)
+ x_offset = settings_table.x_offset
+ y_offset = settings_table.y_offset
+ selector_pos.x = 102 + x_offset
+
+ windower.prim.set_position('menu_backdrop',selector_pos.x,y_offset)
+ windower.prim.set_position('selector_rectangle',selector_pos.x,y_offset)
+ windower.prim.set_position('scroll_bar',selector_pos.x + 150,y_offset)
+
+ display_text:pos(95 + x_offset, y_offset)
+
+ menu_icon:pos(-12 + x_offset, -22 + y_offset)
+ menu_icon:show()
+end)
+
+function get_templates()
+ if not windower.ffxi.get_info().logged_in then return end
+ local player = windower.ffxi.get_player()
+ player_info.id = player.id
+ player_info.main_job = main_job_id or player.main_job_id
+ player_info.sub_job = sub_job_id or player.sub_job_id
+ player_info.main_job_level = main_job_level or player.main_job_level
+ player_info.sub_job_level = sub_job_level or player.sub_job_level
+
+ local main = res.jobs[player_info.main_job].en
+ local sub = res.jobs[player_info.sub_job].en
+
+ local t_temp = L(res.spells:levels(function(t) return t[player_info.main_job] or t[player_info.sub_job] end):keyset())
+ spells_template = loadfile(windower.addon_path .. 'data/spells_template.lua')
+ if not spells_template then
+ print('No template for spells was found.')
+ spells_template = t_temp
+ else
+ spells_template = spells_template()
+ count_table_elements(spells_template)
+ end
+
+ t_temp = L(res.weapon_skills:keyset())
+ ws_template = loadfile(windower.addon_path .. 'data/ws_template.lua')
+ if not ws_template then
+ print('No template for weapon skills was found.')
+ ws_template = t_temp
+ else
+ ws_template = ws_template()
+ count_table_elements(ws_template)
+ if ws_template[main] then
+ if ws_template[sub] then
+ ws_template = recursively_merge_tables(ws_template[main], ws_template[sub])
+ else
+ ws_template = recursively_merge_tables(ws_template[main],t_temp)
+ end
+ elseif ws_template[sub] then
+ ws_template = recursively_merge_tables(ws_template[sub],t_temp)
+ else
+ ws_template = t_temp
+ end
+ end
+
+ t_temp = L(res.job_abilities:prefix('/jobability'):keyset())
+ ja_template = loadfile(windower.addon_path .. 'data/ja_template.lua')
+ if not ja_template then
+ print('No template for job abilities was found.')
+ ja_template = t_temp
+ else
+ ja_template = ja_template()
+ count_table_elements(ja_template)
+ if ja_template[main] then
+ if ja_template[sub] then
+ ja_template = recursively_merge_tables(ja_template[main], ja_template[sub])
+ else
+ ja_template = recursively_merge_tables(ja_template[main],t_temp)
+ end
+ elseif ja_template[sub] then
+ ja_template = recursively_merge_tables(ja_template[sub],t_temp)
+ else
+ ja_template = t_temp
+ end
+ end
+
+ t_temp = L(res.job_abilities:prefix('/pet'):keyset())
+ pet_command_template = loadfile(windower.addon_path .. 'data/pet_command_template.lua')
+ if not pet_command_template then
+ print('No template for pet commands was found.')
+ pet_command_template = t_temp
+ else
+ pet_command_template = pet_command_template()
+ count_table_elements(pet_command_template)
+ if pet_command_template[main] then
+ if pet_command_template[sub] then
+ pet_command_template = recursively_merge_tables(pet_command_template[main], pet_command_template[sub])
+ else
+ pet_command_template = recursively_merge_tables(pet_command_template[main],t_temp)
+ end
+ elseif pet_command_template[sub] then
+ pet_command_template = recursively_merge_tables(pet_command_template[sub],t_temp)
+ else
+ pet_command_template = t_temp
+ end
+ end
+
+ spell_aliases = loadfile(windower.addon_path .. 'data/spell_aliases.lua')
+ if not spell_aliases then
+ spell_aliases = {}
+ else
+ spell_aliases = spell_aliases()
+ end
+
+end
+
+function menu_general_layout(t,t2,n)
+ available_category = t
+ if is_menu_open then
+ if last_menu_open.type == n then
+ is_menu_open = false
+ menu_layer_record:clear()
+ close_a_menu()
+ last_menu_open = {}
+ current_menu = {}
+ menu_history[n] = false
+ else
+ menu_history[last_menu_open.type] = list.copy(menu_layer_record)
+ if menu_history[n] then
+ last_menu_open.type = n
+ menu_layer_record = menu_history[n]
+ current_menu = recursively_copy_spells(t2)
+ if current_menu then
+ last_menu_open = current_menu
+ last_menu_open.type = n
+ for i = 1,menu_layer_record.n do
+ if current_menu[menu_layer_record[i]] then
+ current_menu = current_menu[menu_layer_record[i]]
+ else
+ for j = 1,menu_layer_record.n+1-i do
+ menu_layer_record:remove()
+ end
+ break
+ end
+ end
+ build_a_menu(current_menu)
+ else
+ close_a_menu()
+ current_menu = {}
+ end
+ else
+ menu_layer_record:clear()
+ last_menu_open.type = n
+ current_menu = recursively_copy_spells(t2)
+ if current_menu then
+ last_menu_open = current_menu
+ last_menu_open.type = n
+ build_a_menu(current_menu)
+ else
+ close_a_menu()
+ current_menu = {}
+ end
+ end
+ end
+ else
+ if menu_history[n] then
+ last_menu_open.type = n
+ menu_layer_record = menu_history[n]
+ current_menu = recursively_copy_spells(t2)
+ if current_menu then
+ last_menu_open = current_menu
+ last_menu_open.type = n
+ for i = 1,menu_layer_record.n do
+ if current_menu[menu_layer_record[i]] then
+ current_menu = current_menu[menu_layer_record[i]]
+ else
+ for j = 1,menu_layer_record.n+1-i do
+ menu_layer_record:remove()
+ end
+ break
+ end
+ end
+ build_a_menu(current_menu)
+ else
+ close_a_menu()
+ current_menu = {}
+ end
+ else
+ menu_layer_record:clear()
+ last_menu_open.type = n
+ current_menu = recursively_copy_spells(t2)
+ if current_menu then
+ last_menu_open = current_menu
+ last_menu_open.type = n
+ build_a_menu(current_menu)
+ else
+ close_a_menu()
+ current_menu = {}
+ end
+ end
+ end
+end
+
+windower.register_event('incoming chunk', function(id, data)
+ if is_menu_open and id == 0x0AC and last_menu_open.type ~= 1 then
+ if not S(windower.ffxi.get_abilities()[category_to_resources[last_menu_open.type]]):equals(available_category) then
+ available_category = S(windower.ffxi.get_abilities()[category_to_resources[last_menu_open.type]])
+ current_menu = recursively_copy_spells({spells_template,ws_template,ja_template,pet_command_template}[last_menu_open.type])
+ menu_building_snippet()
+ end
+ end
+end)
+
+windower.register_event('gain buff', function(buff_id)
+ if is_menu_open and refresh_ma_when[buff_id] and last_menu_open.type == 1 then
+ active_buffs:add(buff_id)
+ number_of_jps = count_job_points()
+ current_menu = recursively_copy_spells(spells_template)
+ menu_building_snippet()
+ end
+end)
+
+windower.register_event('lose buff', function(buff_id)
+ if is_menu_open and refresh_ma_when[buff_id] and last_menu_open.type == 1 then
+ active_buffs:remove(buff_id)
+ number_of_jps = count_job_points()
+ current_menu = recursively_copy_spells(spells_template)
+ menu_building_snippet()
+ end
+end)
+
+windower.register_event('job change',get_templates)
+
+windower.register_event('login', function()
+ get_templates:schedule(10)
+end)
+
+windower.register_event('load', function()
+ get_templates()
+end)
+
+windower.register_event('logout', function()
+ close_a_menu()
+ display_text:hide()
+ menu_icon:hide()
+end)
+
+windower.register_event('mouse', function(type, x, y, delta, blocked)
+ if blocked then
+ return
+ end
+ if type == 0 then
+ local _x,_y = x-(51+x_offset),y-(51+y_offset)
+ if drag_and_drop then
+ x_offset = x-drag_and_drop.x
+ y_offset = y-drag_and_drop.y
+ display_text:pos(x_offset+95,y_offset)
+ menu_icon:pos(x_offset-12,y_offset-22)
+ selector_pos.x = x_offset+102
+ windower.prim.set_position('menu_backdrop',selector_pos.x,y-drag_and_drop.y)
+ windower.prim.set_position('selector_rectangle',selector_pos.x,y_offset+selector_pos.y)
+ windower.prim.set_position('scroll_bar',selector_pos.x + 150,y_offset + ((12 * font_height_est * (1 - 12 / menu_list.n)) / (menu_list.n - 12)) * (menu_start - 1))
+ elseif math.abs(_x) + math.abs(_y) <= 51 then
+ local tan = (_y)/(_x)
+ if _x > 0 then
+ if tan <= -1 then
+ if not is_icon.G then
+ menu_icon:color(111,255,111)
+ colors_of_the_wind('G')
+ end
+ elseif tan >= -1 and tan <= 1 then
+ if not is_icon.R then
+ menu_icon:color(255,111,111)
+ colors_of_the_wind('R')
+ end
+ elseif tan >= 1 then
+ if not is_icon.B then
+ menu_icon:color(111,111,255)
+ colors_of_the_wind('B')
+ end
+ end
+ elseif _x < 0 then
+ if tan <= -1 then
+ if not is_icon.B then
+ menu_icon:color(111,111,255)
+ colors_of_the_wind('B')
+ end
+ elseif tan >= -1 and tan <= 1 then
+ if not is_icon.Y then
+ menu_icon:color(255,255,111)
+ colors_of_the_wind('Y')
+ end
+ elseif tan >= 1 then
+ if not is_icon.G then
+ menu_icon:color(111,255,111)
+ colors_of_the_wind('G')
+ end
+ end
+ end
+ elseif is_menu_open then
+ if (x >= display_text:pos_x() and x <= display_text:pos_x() + 150) then
+ local _,_y = display_text:extents()
+ if y <= y_offset or y >= y_offset + _y then return end
+ local y_17 = math.ceil((y-y_offset)/font_height_est)
+ if (y_17) ~= selector_pos.y then
+ selector_pos.y = (y_17 - 1) * font_height_est
+ windower.prim.set_position('selector_rectangle',selector_pos.x,selector_pos.y + y_offset)
+ end
+ else
+ if not is_icon[letter_to_n[last_menu_open.type]] then
+ menu_icon:color(unpack(n_to_color[last_menu_open.type]))
+ colors_of_the_wind(letter_to_n[last_menu_open.type])
+ end
+ end
+ elseif not is_icon.W then
+ menu_icon:color(255,255,255)
+ colors_of_the_wind('W')
+ end
+ elseif type == 1 then
+ local _x,_y = x-(51+x_offset),y-(51+y_offset)
+ if math.abs(_x) + math.abs(_y) <= 51 then
+ mouse_safety = true
+ if is_shift_modified then
+ drag_and_drop = {x=_x+51,y=_y+51}
+ return true
+ else
+ local tan = (_y)/(_x)
+ if _x >= 0 then
+ if tan <= -1 then
+ mouse_func[2]()
+ elseif tan >= -1 and tan <= 1 then
+ mouse_func[1]()
+ elseif tan >= 1 then
+ mouse_func[3]()
+ end
+ elseif _x < 0 then
+ if tan <= -1 then
+ mouse_func[3]()
+ elseif tan >= -1 and tan <= 1 then
+ mouse_func[4]()
+ elseif tan >= 1 then
+ mouse_func[2]()
+ end
+ end
+ return true
+ end
+ elseif is_menu_open and x >= display_text:pos_x() and x <= display_text:pos_x() + 150 then
+ local _,_y = display_text:extents()
+ if y <= y_offset or y >= y_offset + _y then return end
+
+ local y_17 = math.ceil((y-y_offset)/font_height_est + menu_start - 1)
+ if current_menu.sub_menus and y_17 <= current_menu.sub_menus.n then
+ menu_layer_record:append(current_menu.sub_menus[y_17])
+ current_menu = current_menu[menu_layer_record:last()]
+ build_a_menu(current_menu)
+ mouse_safety = true
+ return true
+ else
+ format_response(last_menu_open.type,current_menu[y_17-(current_menu.sub_menus and current_menu.sub_menus.n or 0)],is_shift_modified)
+ mouse_safety = true
+ return true
+ end
+ end
+ elseif type == 2 then
+ if drag_and_drop then
+ _defaults.x_offset = x_offset
+ _defaults.y_offset = y_offset
+ _defaults:save()
+ drag_and_drop = false
+ end
+ if mouse_safety then
+ mouse_safety = false
+ return true
+ end
+ elseif type == 10 then
+ if is_menu_open and menu_list.n > 12
+ and x >= display_text:pos_x() and x<= display_text:pos_x() + 150
+ and y >= display_text:pos_y() and y <= display_text:pos_y() + 12 * font_height_est then
+
+ menu_start = menu_start - delta
+ if menu_start < 1 then menu_start = 1 end
+ if menu_start + 11 > menu_list.n then menu_start = menu_list.n - 11 end
+ display_text:text(menu_list:concat('\n',menu_start,menu_start+11))
+ windower.prim.set_position('scroll_bar',selector_pos.x + 150,y_offset + ((12 * font_height_est * (1 - 12 / menu_list.n)) / (menu_list.n - 12)) * (menu_start - 1))
+ return true
+ end
+ elseif type == 4 then
+ local _x,_y = x-(51+x_offset),y-(51+y_offset)
+ if math.abs(_x) + math.abs(_y) <= 51 then
+ mouse_safety = true
+ if is_menu_open then
+ menu_history[last_menu_open.type] = list.copy(menu_layer_record)
+ end
+ close_a_menu()
+ return true
+ elseif is_menu_open and x >= display_text:pos_x() and x <= display_text:pos_x() + 150 then
+ if y <= y_offset or y >= y_offset + font_height_est * 12 then return end
+ if menu_layer_record.n == 0 then
+ close_a_menu()
+ else
+ open_previous_menu()
+ end
+ mouse_safety = true
+ return true
+ end
+ elseif type == 5 then
+ if mouse_safety then
+ mouse_safety = false
+ return true
+ end
+ end
+end)
+
+mouse_func = {
+ [1] = function()
+ active_buffs = S(windower.ffxi.get_player().buffs)
+ number_of_jps = count_job_points()
+ menu_general_layout(windower.ffxi.get_spells(),spells_template,1)
+ end,
+ [2] = function()
+ menu_general_layout(S(windower.ffxi.get_abilities().weapon_skills),ws_template,2)
+ end,
+ [3] = function()
+ menu_general_layout(S(remove_categories(windower.ffxi.get_abilities().job_abilities)),ja_template,3)
+ end,
+ [4] = function()
+ menu_general_layout(S(remove_categories(windower.ffxi.get_abilities().job_abilities)),pet_command_template,4)
+ end,
+}
+
+function build_a_menu(t)
+ menu_start = 1
+ is_menu_open = true
+ menu_list:clear()
+ if t.sub_menus and (t.sub_menus.n + t.n == 1) then
+ menu_layer_record:append(current_menu.sub_menus[1])
+ current_menu = current_menu[menu_layer_record:last()]
+ build_a_menu(current_menu)
+ else
+ if t.sub_menus then
+ for i = 1,t.sub_menus.n do
+ menu_list:append(' \\cs(' .. (custom_menu_colors[t.sub_menus[i]] or '239,195,255') .. ')' .. t.sub_menus[i] .. '\\cr')
+ end
+ end
+ for i = 1,t.n do
+ menu_list:append(' ' .. get_string_from_id(t[i]))
+ end
+ if menu_list.n > 12 then
+ windower.prim.set_size('scroll_bar',10,(font_height_est * 144 / menu_list.n))
+ windower.prim.set_visibility('scroll_bar',true)
+ windower.prim.set_position('scroll_bar',selector_pos.x + 150,y_offset)
+ else
+ windower.prim.set_visibility('scroll_bar',false)
+ end
+ display_text:text(menu_list:concat('\n',1,12))
+ windower.prim.set_visibility('menu_backdrop',true)
+ selector_pos.y = y_offset
+ windower.prim.set_position('selector_rectangle',selector_pos.x,selector_pos.y)
+ windower.prim.set_visibility('selector_rectangle',true)
+ display_text:show()
+ end
+end
+
+function close_a_menu()
+ is_menu_open = false
+ menu_layer_record:clear()
+ windower.prim.set_visibility('scroll_bar',false)
+ windower.prim.set_visibility('menu_backdrop',false)
+ windower.prim.set_visibility('selector_rectangle',false)
+ display_text:hide()
+end
+
+function open_previous_menu()
+ menu_layer_record:remove()
+ current_menu = last_menu_open
+ for i = 1,menu_layer_record.n do
+ current_menu = current_menu[menu_layer_record[i]]
+ end
+ if current_menu.sub_menus and (current_menu.sub_menus.n + current_menu.n == 1) then
+ if menu_layer_record.n == 0 then
+ close_a_menu()
+ else
+ open_previous_menu()
+ end
+ else
+ build_a_menu(current_menu)
+ end
+end
+
+function format_response(n,p,bool)
+ local t
+ if n == 1 then
+ if bool then
+ if not (res.spells[p].targets['Self'] or res.spells[p].targets['Corpse']) then
+ t = ' <stnpc>'
+ else
+ t = ' <stpc>'
+ end
+ else
+ t = ''
+ end
+ n,p = '/ma',res.spells[p].en
+ elseif n == 2 then
+ if bool then
+ if not (res.weapon_skills[p].targets['Self'] or res.weapon_skills[p].targets['Corpse']) then
+ t = ' <stnpc>'
+ else
+ t = ' <stpc>'
+ end
+ else
+ t = ''
+ end
+ n,p = '/ws',res.weapon_skills[p].en
+ else
+ if bool then
+ if not (res.job_abilities[p].targets['Self'] or res.job_abilities[p].targets['Corpse']) then
+ t = ' <stnpc>'
+ else
+ t = ' <stpc>'
+ end
+ else
+ t = ''
+ end
+ n,p = res.job_abilities[p].prefix,res.job_abilities[p].en
+ end
+
+ windower.send_command('input %s %q%s':format(n,p,t))
+end
+
+windower.register_event('keyboard', function(dik, down, flags, blocked)
+ if dik == 42 and not bit.is_set(flags, 6) then
+ is_shift_modified = down
+ end
+end)
+
+function determine_accessibility(spell,type) -- ability filter, slightly modified. Credit: Byrth
+ if type == 1 then
+ local spell_jobs = spell.levels
+ if not available_category[spell.id] and not (spell.id == 503) then
+ return false
+ elseif (not spell_jobs[player_info.main_job] or not (spell_jobs[player_info.main_job] <= player_info.main_job_level or
+ (spell_jobs[player_info.main_job] > 99 and number_of_jps >= spell_jobs[player_info.main_job]))) and
+ (not spell_jobs[player_info.sub_job] or not (spell_jobs[player_info.sub_job] <= player_info.sub_job_level)) then
+ return false
+ elseif player_info.main_job == 20 and ((addendum_white[spell.id] and not active_buffs[401] and not active_buffs[416]) or
+ (addendum_black[spell.id] and not active_buffs[402] and not active_buffs[416])) and
+ not (spell_jobs[player_info.sub_job] and spell_jobs[player_info.sub_job] <= player_info.sub_job_level) then
+ return false
+ elseif player_info.sub_job == 20 and ((addendum_white[spell.id] and not active_buffs[401] and not active_buffs[416]) or
+ (addendum_black[spell.id] and not active_buffs[402] and not active_buffs[416])) and
+ not (spell_jobs[player_info.main_job] and spell_jobs[player_info.main_job] <= player_info.main_job_level) then
+ return false
+ elseif spell.type == 'BlueMagic' and not ((player_info.main_job == 16 and table.contains(windower.ffxi.get_mjob_data().spells,spell.id)) or
+ ((active_buffs[485] or active_buffs[505]) and unbridled_learning_set[spell.english])) and not
+ (player.sub_job_id == 16 and table.contains(windower.ffxi.get_sjob_data().spells,spell.id)) then
+ return false
+ end
+ return true
+ else
+ return available_category:contains(spell.id)
+ end
+end