summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch
diff options
context:
space:
mode:
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/pointwatch')
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/FIXING POINTWATCH.txt35
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/ReadMe.txt79
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/message_ids.lua189
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/pointwatch.lua328
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/statics.lua159
5 files changed, 790 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/FIXING POINTWATCH.txt b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/FIXING POINTWATCH.txt
new file mode 100644
index 0000000..61bb39c
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/FIXING POINTWATCH.txt
@@ -0,0 +1,35 @@
+Updating Message IDs: A guide
+
+ Pointwatch relies on zone-based message IDs for some of its features.
+These IDs change on a regular basis. Fortunately, their positions relative
+to one another rarely change, which means that most of the time you only
+have to change one number and the entire zone will work again.
+
+I have written this guide to explain how to change those numbers in the
+hopes that members of the community will maintain pointwatch's message-
+dependent features.
+
+Method 1 - POLUtils
+1) Download POLUtils (if you don't already have it) from the google code site
+2) Install it and run it
+3) Click "FFXI Data Browser"
+4) Go to the "Dialog Tables" menu and select the zone you are interested in
+5) Wait for it to load, then export the entire table as xml
+6) Open the xml file up in a text editor, like Notepad or Notepad++.
+7) Control-F for the key phrase.
+8) The associated message ID is the offset value for that zone.
+
+Method 2 - message_printing
+1) Load Pointwatch (//lua l pointwatch)
+2) Enable message printing (//pw message_printing)
+3) Generate the key message (for instance, by resting in Abyssea)
+4) This will print message IDs to your windower console. They appear in the
+ order they were generated. Select the one that you want (for instance,
+ the second one when you rest in Abyssea).
+5) That value is your offset.
+6) Disable message printing (//pw message_printing)
+
+Both methods:
+* Open message_ids.lua
+* Find the zone and replace the zone.offset value with the correct value.
+* Submit your file to Github, so that everyone can have a working copy!
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/ReadMe.txt b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/ReadMe.txt
new file mode 100644
index 0000000..b3f1964
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/ReadMe.txt
@@ -0,0 +1,79 @@
+=== PointWatch ===
+Allows you to monitor your XP/CP gains and keep track of the Dynamis time limit.
+
+Abbreviation: //pw
+
+Text Box Commands:
+* show - Shows the text box.
+* hide - Hides the text box.
+* pos <X> <Y> - Moves the upper left corner of the text box to the coordinates X/Y.
+* font <font name> - Changes the text's font.
+* size <point size> - Changes the size of the text's font.
+* color <R> <G> <B> - Changes the text color. Numbers should be between 0 and 255.
+* bg_color <R> <G> <B> - Changes the background color. Numbers should be between 0 and 255.
+* bg_transparency <number> - Changes the background transparency. Number should be between 0 and 1
+** pos_x, pos_y, pad, transparency, alpha, and bg_alpha are also valid commands and are documented in the texts library.
+
+Other Commands:
+* message_printing - See FIXING POINTWATCH.txt in this directory for a full explanation.
+
+
+
+Strings Options:
+The two strings options in settings.xml are loaded as Lua code and run accordingly,
+so you can do things like adjust numbers and format things as you wish. The default
+is designed to look somewhat like the Attainment plugin, but you are free to change
+it however you wish. Be aware that the code will give very unhelpful errors when it fails.
+
+Here are the available values:
+* xp.current = Current Experience Points (number from 0 to 55,999 XP)
+* xp.tnl = Number of Experience Points in your current level (number from 500 to 56,000)
+* xp.rate = Current XP gain rate per hour. This is calculated over a 10 minute window and requires at least two gains within the window.
+* xp.total = Total Experience Points gained since the last time the addon was loaded (number)
+
+* lp.current = Current Experience Points (number from 0 to 55,999 XP)
+* lp.tnl = Similar to a "To Next Level", but this value is always 10,000 because that's always the number of Limit Points per merit point.
+* lp.number_of_merits = Number of merit points you have.
+* lp.maximum_merits = Maximum number of merits you can store.
+
+* cp.current = Current Capacity Points (number from 0 to 29,999 CP)
+* cp.rate = Current CP gain rate per hour. This is calculated over a 10 minute window and requires at least two gains within the window.
+* cp.total = Total Capacity Points gained since the last time the addon was loaded (number)
+* cp.tnjp = Similar to a "To Next Level", but this value is always 30,000 because that's always the number of CPs per job point.
+* cp.number_of_job_points = Number of job points you currently have on your current job.
+
+* sparks.current = Current number of RoE Sparks (number between 0 and 50,000)
+* sparks.maximum = Maximum number of RoE Sparks (always 50,000)
+
+* accolades.current = Current number of Unity Accolades (number between 0 and 50,000)
+* accolades.maximum = Maximum number of Unity Accolades (always 50,000)
+
+* dynamis.KIs = Series of Xs and Os indicating whether or not you have the 5 KIs.
+* dynamis.entry_time = Your Dynamis entry time, in seconds. -- If the addon is loaded in dynamis, this will be the time of addon load.
+* dynamis.time_limit = Your current Dynamis time limit, in seconds. -- If the addon is loaded in dynamis, you will need to gain a KI for this to be accurate.
+* dynamis.time_remaining = The current dynamis time remaining, in seconds. -- Will not be accurate if the addon is loaded in dynamis.
+
+* abyssea.amber = Amber light estimation
+* abyssea.azure = Azure light estimation
+* abyssea.ruby = Ruby light estimation
+* abyssea.pearlescent = Pearlescent light estimation
+* abyssea.golden = Gold light estimation
+* abyssea.silvery = Silvery light estimation
+* abyssea.ebon = Ebon light estimation
+* abyssea.last_time = The last time you got a time message, in seconds. -- Not implemented
+* abyssea.time_limit = The current abyssea time remaining, in seconds. -- Approximate to the minute, not fully implemented
+* abyssea.time_remaining = The current abyssea time remaining, in seconds. -- Approximate to the minute, not fully implemented
+
+
+
+Version History:
+0.150811 - Changed job_points from a char to a short.
+0.150201 - Added Unity Accolades.
+0.141111 - Adjusted Pointwatch to account for a recent packet change.
+0.141101 - Reversed my versioning scheme, adjusted the limit point and experience point calculations slightly.
+0.101214 - Made pointwatch hide itself while zoning.
+0.062014 - Added lp.maximum_merits.
+0.050214 - Fixed the Dynamis clock. Added Abyssea lights.
+0.042314 - Addition of strings system
+0.042014 - Addition of strings system
+0.041214 - Initial commit \ No newline at end of file
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/message_ids.lua b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/message_ids.lua
new file mode 100644
index 0000000..3cd91ff
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/message_ids.lua
@@ -0,0 +1,189 @@
+--Copyright (c) 2014, Byrthnoth
+--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.
+
+-- Offset messages:
+-- Abyssea's offset message is the one that reports your Pearlescent, Ebon, Gold, and Silvery light when you /heal.
+-- Do a Control-F for Pearlescent to find it if using the POLUtils method. It should be the first result.
+
+-- SEE THE "FIXING POINTWATCH" FILE IN THIS FOLDER FOR INSTRUCTIONS ON HOW TO FIX POINTWATCH.
+
+local messages = {
+ z15 = {
+ name = 'Abyssea - Konschtat',
+ offset = 7315,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10,
+ visitant_status_extend = 12,
+ visitant_status_gain = 45,
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+ z132 = {
+ name = 'Abyssea - La Theine',
+ offset = 7315,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10,
+ visitant_status_extend = 12,
+ visitant_status_gain = 45,
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+ z45 = {
+ name = 'Abyssea - Tahrongi',
+ offset = 7315,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10,
+ visitant_status_extend = 12,
+ visitant_status_gain = 45,
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+ z215 = {
+ name = 'Abyssea - Attohwa',
+ offset = 7215,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10, -- Could also be 7194, the singular message. That is less than 10 minutes though, so shouldn't need to update for it.
+ visitant_status_extend = 12,
+ visitant_status_gain = 45, -- Could also be 7228 or 7229
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+ z216 = {
+ name = 'Abyssea - Misareaux',
+ offset = 7315,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10,
+ visitant_status_extend = 12,
+ visitant_status_gain = 45,
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+ z217 = {
+ name = 'Abyssea - Vunkerl',
+ offset = 7315,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10,
+ visitant_status_extend = 12,
+ visitant_status_gain = 45,
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+ z218 = {
+ name = 'Abyssea - Altepa',
+ offset = 7315,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10,
+ visitant_status_extend = 12,
+ visitant_status_gain = 45,
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+ z254 = {
+ name = 'Abyssea - Grauberg',
+ offset = 7315,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10,
+ visitant_status_extend = 12,
+ visitant_status_gain = 45,
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+ z253 = {
+ name = 'Abyssea - Uleguerand',
+ offset = 7215,
+ pearl_ebon_gold_silvery = 0,
+ azure_ruby_amber = 1,
+ visitant_status_update = 9,
+ visitant_status_wears_off = 10,
+ visitant_status_extend = 12,
+ visitant_status_gain = 45,
+ pearlescent_light = 183,
+ golden_light = 184,
+ silvery_light = 185,
+ ebon_light = 186,
+ azure_light = 187,
+ ruby_light = 188,
+ amber_light = 189,
+ },
+}
+
+return messages
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/pointwatch.lua b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/pointwatch.lua
new file mode 100644
index 0000000..8eac64d
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/pointwatch.lua
@@ -0,0 +1,328 @@
+--Copyright (c) 2014, Byrthnoth
+--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.
+
+texts = require 'texts'
+config = require 'config'
+require 'sets'
+res = require 'resources'
+require 'statics'
+messages = require 'message_ids'
+require 'pack'
+
+_addon.name = 'PointWatch'
+_addon.author = 'Byrth'
+_addon.version = 0.150811
+_addon.command = 'pw'
+
+settings = config.load('data\\settings.xml',default_settings)
+config.register(settings,initialize)
+
+box = texts.new('${current_string}',settings.text_box_settings,settings)
+box.current_string = ''
+box:show()
+
+initialize()
+
+windower.register_event('incoming chunk',function(id,org,modi,is_injected,is_blocked)
+ if is_injected then return end
+ if id == 0x29 then -- Action Message, used in Abyssea for xp
+ local val = org:unpack('I',0xD)
+ local msg = org:unpack('H',0x19)%1024
+ exp_msg(val,msg)
+ elseif id == 0x2A then -- Resting message
+ local zone = 'z'..windower.ffxi.get_info().zone
+ if settings.options.message_printing then
+ print('Message ID: '..(org:unpack('H',0x1B)%2^14))
+ end
+
+ if messages[zone] then
+ local msg = org:unpack('H',0x1B)%2^14
+ for i,v in pairs(messages[zone]) do
+ if tonumber(v) and v + messages[zone].offset == msg then
+ local param_1 = org:unpack('I',0x9)
+ local param_2 = org:unpack('I',0xD)
+ local param_3 = org:unpack('I',0x11)
+ local param_4 = org:unpack('I',0x15)
+ -- print(param_1,param_2,param_3,param_4) -- DEBUGGING STATEMENT -------------------------
+ if zone_message_functions[i] then
+ zone_message_functions[i](param_1,param_2,param_3,param_4)
+ end
+ if i:contains("visitant_status_") then
+ abyssea.update_time = os.clock()
+ end
+ end
+ end
+ end
+ elseif id == 0x2D then
+ local val = org:unpack('I',0x11)
+ local msg = org:unpack('H',0x19)%1024
+ exp_msg(val,msg)
+ elseif id == 0x55 then
+ if org:byte(0x85) == 3 then
+ local dyna_KIs = math.floor((org:byte(6)%64)/2) -- 5 bits (32, 16, 8, 4, and 2 originally -> shifted to 16, 8, 4, 2, and 1)
+ dynamis._KIs = {
+ ['Crimson'] = dyna_KIs%2 == 1,
+ ['Azure'] = math.floor(dyna_KIs/2)%2 == 1,
+ ['Amber'] = math.floor(dyna_KIs/4)%2 == 1,
+ ['Alabaster'] = math.floor(dyna_KIs/8)%2 == 1,
+ ['Obsidian'] = math.floor(dyna_KIs/16) == 1,
+ }
+ if dynamis_map[dynamis.zone] then
+ dynamis.time_limit = 3600
+ for KI,TE in pairs(dynamis_map[dynamis.zone]) do
+ if dynamis._KIs[KI] then
+ dynamis.time_limit = dynamis.time_limit + TE*60
+ end
+ end
+ update_box()
+ end
+ end
+ elseif id == 0x61 then
+ xp.current = org:unpack('H',0x11)
+ xp.tnl = org:unpack('H',0x13)
+ accolades.current = math.floor(org:byte(0x5A)/4) + org:byte(0x5B)*2^6 + org:byte(0x5C)*2^14
+ elseif id == 0x63 and org:byte(5) == 2 then
+ lp.current = org:unpack('H',9)
+ lp.number_of_merits = org:byte(11)%128
+ lp.maximum_merits = org:byte(0x0D)%128
+ elseif id == 0x63 and org:byte(5) == 5 then
+ local offset = windower.ffxi.get_player().main_job_id*6+13 -- So WAR (ID==1) starts at byte 19
+ cp.current = org:unpack('H',offset)
+ cp.number_of_job_points = org:unpack('H',offset+2)
+ elseif id == 0x110 then
+ sparks.current = org:unpack('I',5)
+ elseif id == 0xB and box:visible() then
+ zoning_bool = true
+ box:hide()
+ elseif id == 0xA and zoning_bool then
+ zoning_bool = nil
+ box:show()
+ end
+end)
+
+windower.register_event('zone change',function(new,old)
+ if res.zones[new].english:sub(1,7) == 'Dynamis' then
+ dynamis.entry_time = os.clock()
+ abyssea.update_time = 0
+ abyssea.time_remaining = 0
+ dynamis.time_limit = 3600
+ dynamis.zone = new
+ cur_func,loadstring_err = loadstring("current_string = "..settings.strings.dynamis)
+ elseif res.zones[new].english:sub(1,7) == 'Abyssea' then
+ abyssea.update_time = os.clock()
+ abyssea.time_remaining = 5
+ dynamis.entry_time = 0
+ dynamis.time_limit = 0
+ dynamis.zone = 0
+ cur_func,loadstring_err = loadstring("current_string = "..settings.strings.abyssea)
+ else
+ abyssea.update_time = 0
+ abyssea.time_remaining = 0
+ dynamis.entry_time = 0
+ dynamis.time_limit = 0
+ dynamis.zone = 0
+ cur_func,loadstring_err = loadstring("current_string = "..settings.strings.default)
+ end
+ if not cur_func or loadstring_err then
+ cur_func = loadstring("current_string = ''")
+ error(loadstring_err)
+ end
+end)
+
+windower.register_event('addon command',function(...)
+ local commands = {...}
+ local first_cmd = table.remove(commands,1):lower()
+ if approved_commands[first_cmd] and #commands >= approved_commands[first_cmd].n then
+ local tab = {}
+ for i,v in ipairs(commands) do
+ tab[i] = tonumber(v) or v
+ if i <= approved_commands[first_cmd].n and type(tab[i]) ~= approved_commands[first_cmd].t then
+ print('Pointwatch: texts library command ('..first_cmd..') requires '..approved_commands[first_cmd].n..' '..approved_commands[first_cmd].t..'-type input'..(approved_commands[first_cmd].n > 1 and 's' or ''))
+ return
+ end
+ end
+ texts[first_cmd](box,unpack(tab))
+ settings.text_box_settings = box._settings
+ config.save(settings)
+ elseif first_cmd == 'reload' then
+ windower.send_command('lua r pointwatch')
+ elseif first_cmd == 'unload' then
+ windower.send_command('lua u pointwatch')
+ elseif first_cmd == 'reset' then
+ initialize()
+ elseif first_cmd == 'message_printing' then
+ settings.options.message_printing = not settings.options.message_printing
+ print('Pointwatch: Message printing is '..tostring(settings.options.message_printing)..'.')
+ elseif first_cmd == 'eval' then
+ assert(loadstring(table.concat(commands, ' ')))()
+ end
+end)
+
+windower.register_event('prerender',function()
+ if frame_count%30 == 0 and box:visible() then
+ update_box()
+ end
+ frame_count = frame_count + 1
+end)
+
+function update_box()
+ if not windower.ffxi.get_info().logged_in or not windower.ffxi.get_player() then
+ box.current_string = ''
+ return
+ end
+ cp.rate = analyze_points_table(cp.registry)
+ xp.rate = analyze_points_table(xp.registry)
+ if dynamis.entry_time ~= 0 and dynamis.entry_time+dynamis.time_limit-os.clock() > 0 then
+ dynamis.time_remaining = os.date('!%H:%M:%S',dynamis.entry_time+dynamis.time_limit-os.clock())
+ dynamis.KIs = X_or_O(dynamis._KIs.Crimson)..X_or_O(dynamis._KIs.Azure)..X_or_O(dynamis._KIs.Amber)..X_or_O(dynamis._KIs.Alabaster)..X_or_O(dynamis._KIs.Obsidian)
+ elseif abyssea.update_time ~= 0 then
+ local time_less_then = math.floor((os.clock() - abyssea.update_time)/60)
+ abyssea.time_remaining = abyssea.time_remaining-time_less_then
+ if time_less_then >= 1 then
+ abyssea.update_time = os.clock()
+ end
+ else
+ dynamis.time_remaining = 0
+ dynamis.KIs = ''
+ end
+ assert(cur_func)()
+
+ if box.current_string ~= current_string then
+ box.current_string = current_string
+ end
+end
+
+function X_or_O(bool)
+ if bool then return 'O' else return 'X' end
+end
+
+function analyze_points_table(tab)
+ local t = os.clock()
+ local running_total = 0
+ local maximum_timestamp = 29
+ for ts,points in pairs(tab) do
+ local time_diff = t - ts
+ if t - ts > 600 then
+ tab[ts] = nil
+ else
+ running_total = running_total + points
+ if time_diff > maximum_timestamp then
+ maximum_timestamp = time_diff
+ end
+ end
+ end
+
+ local rate
+ if maximum_timestamp == 29 then
+ rate = 0
+ else
+ rate = math.floor((running_total/maximum_timestamp)*3600)
+ end
+
+ return rate
+end
+
+zone_message_functions = {
+ amber_light = function(p1,p2,p3,p4)
+ abyssea.amber = math.min(abyssea.amber + 8,255)
+ end,
+ azure_light = function(p1,p2,p3,p4)
+ abyssea.azure = math.min(abyssea.azure + 8,255)
+ end,
+ ruby_light = function(p1,p2,p3,p4)
+ abyssea.ruby = math.min(abyssea.ruby + 8,255)
+ end,
+ pearlescent_light = function(p1,p2,p3,p4)
+ abyssea.pearlescent = math.min(abyssea.pearlescent + 5,230)
+ end,
+ ebon_light = function(p1,p2,p3,p4)
+ abyssea.ebon = math.min(abyssea.ebon + p1+1,200) -- NM kill = 1, faint = 1, mild = 2, strong = 3
+ end,
+ silvery_light = function(p1,p2,p3,p4)
+ abyssea.silvery = math.min(abyssea.silvery + 5*(p1+1),200) -- faint = 5, mild = 10, strong = 15
+ end,
+ golden_light = function(p1,p2,p3,p4)
+ abyssea.golden = math.min(abyssea.golden + 5*(p1+1),200) -- faint = 5, mild = 10, strong = 15
+ end,
+ pearl_ebon_gold_silvery = function(p1,p2,p3,p4)
+ abyssea.pearlescent = p1
+ abyssea.ebon = p2
+ abyssea.golden = p3
+ abyssea.silvery = p4
+ end,
+ azure_ruby_amber = function(p1,p2,p3,p4)
+ abyssea.azure = p1
+ abyssea.ruby = p2
+ abyssea.amber = p3
+ end,
+ visitant_status_gain = function(p1,p2,p3,p4)
+ abyssea.time_remaining = p1
+ end,
+ visitant_status_update = function(p1,p2,p3,p4)
+ abyssea.time_remaining = p1
+ end,
+ visitant_status_wears_off = function(p1,p2,p3,p4)
+ abyssea.time_remaining = p1
+ end,
+ visitant_status_extend = function(p1,p2,p3,p4)
+ abyssea.time_remaining = abyssea.time_remaining + p1
+ end,
+}
+
+function exp_msg(val,msg)
+ local t = os.clock()
+ if msg == 718 or msg == 735 then
+ cp.registry[t] = (cp.registry[t] or 0) + val
+ cp.total = cp.total + val
+ cp.current = cp.current + val
+ if cp.current > cp.tnjp and cp.number_of_job_points ~= cp.maximum_job_points then
+ cp.number_of_job_points = math.min(cp.number_of_job_points + math.floor(cp.current/cp.tnjp),cp.maximum_job_points)
+ cp.current = cp.current%cp.tnjp
+ end
+ elseif msg == 8 or msg == 105 then
+ xp.registry[t] = (xp.registry[t] or 0) + val
+ xp.total = xp.total + val
+ xp.current = math.min(xp.current + val,55999)
+ -- 98 to 99 is 56000 XP, so 55999 is the most you can ever have
+ if xp.current > xp.tnl then
+ -- I have capped all jobs, but I assume that a 0x61 packet is sent after you
+ -- level up, which will update the TNL and make this adjustment meaningless.
+ xp.current = xp.current - xp.tnl
+ end
+ elseif msg == 371 or msg == 372 then
+ lp.registry[t] = (lp.registry[t] or 0) + val
+ lp.current = lp.current + val
+ if lp.current >= lp.tnm and lp.number_of_merits ~= lp.maximum_merits then
+ -- Merit Point gained!
+ lp.number_of_merits = math.min(lp.number_of_merits + math.floor(lp.current/lp.tnm),lp.maximum_merits)
+ lp.current = lp.current%lp.tnm
+ else
+ -- If a merit point was not gained,
+ lp.current = math.min(lp.current,lp.tnm-1)
+ end
+ end
+ update_box()
+end
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/statics.lua b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/statics.lua
new file mode 100644
index 0000000..902cc46
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/pointwatch/statics.lua
@@ -0,0 +1,159 @@
+--Copyright (c) 2014, Byrthnoth
+--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.
+
+
+--Default settings file:
+default_settings = {
+ strings = {
+ default = "xp.current..'/'..xp.tnl..'XP '..lp.current..'/'..lp.tnm..'LP ['..lp.number_of_merits..'/'..lp.maximum_merits..'] XP/hr:'..string.format('%.1f',math.floor(xp.rate/100)/10)..'k '..cp.current..'/'..cp.tnjp..'CP ['..cp.number_of_job_points..'] CP/hr:'..string.format('%.1f',math.floor(cp.rate/100)/10)..'k'",
+ dynamis = "xp.current..'/'..xp.tnl..'XP '..lp.current..'/'..lp.tnm..'LP ['..lp.number_of_merits..'/'..lp.maximum_merits..'] XP/hr:'..string.format('%.1f',math.floor(xp.rate/100)/10)..'k '..cp.current..'/'..cp.tnjp..'CP ['..cp.number_of_job_points..'] '..dynamis.KIs..' '..dynamis.time_remaining",
+ abyssea = "xp.current..'/'..xp.tnl..'XP '..lp.current..'/'..lp.tnm..'LP ['..lp.number_of_merits..'/'..lp.maximum_merits..'] XP/hr:'..string.format('%.1f',math.floor(xp.rate/100)/10)..'k Amber:'..(abyssea.amber or 0)..'/Azure:'..(abyssea.azure or 0)..'/Ruby:'..(abyssea.ruby or 0)..'/Pearlescent:'..(abyssea.pearlescent or 0)..'/Ebon:'..(abyssea.ebon or 0)..'/Silvery:'..(abyssea.silvery or 0)..'/Golden:'..(abyssea.golden or 0)..'/Time Remaining:'..(abyssea.time_remaining or 0)"
+ },
+ text_box_settings = {
+ pos = {
+ x = 0,
+ y = 0,
+ },
+ bg = {
+ alpha = 255,
+ red = 0,
+ green = 0,
+ blue = 0,
+ visible = true
+ },
+ flags = {
+ right = false,
+ bottom = false,
+ bold = false,
+ italic = false
+ },
+ padding = 0,
+ text = {
+ size = 12,
+ font = 'Consolas',
+ fonts = {},
+ alpha = 255,
+ red = 255,
+ green = 255,
+ blue = 255
+ }
+ },
+ options = {
+ message_printing = false,
+ },
+}
+
+-- Approved textbox commands:
+approved_commands = S{'show','hide','pos','pos_x','pos_y','font','size','pad','color','alpha','transparency','bg_color','bg_alpha','bg_transparency'}
+approved_commands = {show={n=0},hide={n=0},pos={n=2,t='number'},pos_x={n=1,t='number'},pos_y={n=1,t='number'},
+ font={n=2,t='string'},size={n=1,t='number'},pad={n=1,t='number'},color={n=3,t='number'},alpha={n=1,t='number'},
+ transparency={n=1,t='number'},bg_color={n=3,t='number'},bg_alpha={n=1,t='number'},bg_transparency={n=1,t='number'}}
+
+
+-- Dynamis TE lists:
+city_table = {Crimson=10,Azure=10,Amber=10,Alabaster=15,Obsidian=15}
+other_table = {Crimson=10,Azure=10,Amber=10,Alabaster=10,Obsidian=20}
+
+-- Mapping of zone ID to TE list:
+dynamis_map = {[185]=city_table,[186]=city_table,[187]=city_table,[188]=city_table,
+ [134]=other_table,[135]=other_table,[39]=other_table,[40]=other_table,[41]=other_table,[42]=other_table}
+
+
+-- Not technically static, but sets the initial values for all features:
+function initialize()
+ cp = {
+ registry = {},
+ current = 0,
+ rate = 0,
+ total = 0,
+ tnjp = 30000,
+ number_of_job_points = 0,
+ maximum_job_points = 500,
+ }
+
+
+ xp = {
+ registry = {},
+ total = 0,
+ rate = 0,
+ current = 0,
+ tnl = 0,
+ }
+
+ lp = {
+ registry = xp.registry,
+ current = 0,
+ tnm = 10000,
+ number_of_merits = 0,
+ maximum_merits = 30,
+ }
+
+ sparks = {
+ current = 0,
+ maximum = 99999,
+ }
+
+ accolades = {
+ current = 0,
+ maximum = 99999,
+ }
+
+ abyssea = {
+ amber = 0,
+ azure = 0,
+ ruby = 0,
+ pearlescent = 0,
+ ebon = 0,
+ silvery = 0,
+ golden = 0,
+ update_time = 0,
+ time_remaining = 0,
+ }
+
+
+ local info = windower.ffxi.get_info()
+
+ frame_count = 0
+
+ dynamis = {
+ KIs = '',
+ _KIs = {},
+ entry_time = 0,
+ time_limit = 0,
+ zone = 0,
+ }
+ if info.logged_in and res.zones[info.zone].english:sub(1,7) == 'Dynamis' then
+ cur_func = loadstring("current_string = "..settings.strings.dynamis)
+ setfenv(cur_func,_G)
+ dynamis.entry_time = os.clock()
+ dynamis.zone = info.zone
+ windower.add_to_chat(123,'Loading PointWatch in Dynamis results in an inaccurate timer. Number of KIs is displayed.')
+ elseif info.logged_in then
+ cur_func = loadstring("current_string = "..settings.strings.default)
+ setfenv(cur_func,_G)
+ end
+
+end