summaryrefslogtreecommitdiff
path: root/Data/DefaultContent/Libraries/addons/addons/libs/actions.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Data/DefaultContent/Libraries/addons/addons/libs/actions.lua')
-rw-r--r--Data/DefaultContent/Libraries/addons/addons/libs/actions.lua625
1 files changed, 0 insertions, 625 deletions
diff --git a/Data/DefaultContent/Libraries/addons/addons/libs/actions.lua b/Data/DefaultContent/Libraries/addons/addons/libs/actions.lua
deleted file mode 100644
index 14254ce..0000000
--- a/Data/DefaultContent/Libraries/addons/addons/libs/actions.lua
+++ /dev/null
@@ -1,625 +0,0 @@
---[[
-A library to make the manipulation of the action packet easier.
-
-The primary functionality provided here are iterators which allow for
-easy traversal of the sub-tables within the packet. Example:
-
-=======================================================================================
-require('actions')
-
-function event_action(act)
- action = Action(act) -- constructor
-
- -- print out all melee hits to the console
- if actionpacket:get_category_string() == 'melee' then
- for target in actionpacket:get_targets() do -- target iterator
- for action in target:get_actions() do -- subaction iterator
- if action.message == 1 then -- 1 is the code for messages
- print(string.format("%s hit %s for %d damage",
- actionpacket:get_actor_name(), target:get_name(), action.param))
- end
- end
- end
- end
-end
-=======================================================================================
-
-]]
-
-_libs = _libs or {}
-
-require('tables')
-
-local table = _libs.tables
-local res = require('resources')
-
-_libs.actions = true
-
-local category_strings = {
- 'melee',
- 'ranged_finish',
- 'weaponskill_finish',
- 'spell_finish',
- 'item_finish',
- 'job_ability',
- 'weaponskill_begin',
- 'casting_begin',
- 'item_begin',
- 'unknown',
- 'mob_tp_finish',
- 'ranged_begin',
- 'avatar_tp_finish',
- 'job_ability_unblinkable',
- 'job_ability_run'
-}
-
--- ActionPacket operations
-ActionPacket = {}
-
-local actionpacket = {}
--- Constructor for Actions.
--- Usage: actionpacket = ActionPacket(raw_action)
-
-function ActionPacket.new(a)
- if a == nil then
- return
- end
-
- local new_instance = {}
- new_instance.raw = a
-
- return setmetatable(new_instance, {__index = function(t, k) if rawget(t, k) ~= nil then return t[k] else return actionpacket[k] end end})
-end
-
-local function act_to_string(original,act)
- if type(act) ~= 'table' then return act end
-
- function assemble_bit_packed(init,val,initial_length,final_length)
- if not init then return init end
-
- if type(val) == 'boolean' then
- if val then val = 1 else val = 0 end
- elseif type(val) ~= 'number' then
- return false
- end
- local bits = initial_length%8
- local byte_length = math.ceil(final_length/8)
-
- local out_val = 0
- if bits > 0 then
- out_val = init:byte(#init) -- Initialize out_val to the remainder in the active byte.
- init = init:sub(1,#init-1) -- Take off the active byte
- end
- out_val = out_val + val*2^bits -- left-shift val by the appropriate amount and add it to the remainder (now the lsb-s in val)
-
- while out_val > 0 do
- init = init..string.char(out_val%256)
- out_val = math.floor(out_val/256)
- end
- while #init < byte_length do
- init = init..string.char(0)
- end
- return init
- end
-
- local react = assemble_bit_packed(original:sub(1,4),act.size,32,40)
- react = assemble_bit_packed(react,act.actor_id,40,72)
- react = assemble_bit_packed(react,act.target_count,72,82)
- react = assemble_bit_packed(react,act.category,82,86)
- react = assemble_bit_packed(react,act.param,86,102)
- react = assemble_bit_packed(react,act.unknown,102,118)
- react = assemble_bit_packed(react,act.recast,118,150)
-
- local offset = 150
- for i = 1,act.target_count do
- react = assemble_bit_packed(react,act.targets[i].id,offset,offset+32)
- react = assemble_bit_packed(react,act.targets[i].action_count,offset+32,offset+36)
- offset = offset + 36
- for n = 1,act.targets[i].action_count do
- react = assemble_bit_packed(react,act.targets[i].actions[n].reaction,offset,offset+5)
- react = assemble_bit_packed(react,act.targets[i].actions[n].animation,offset+5,offset+17)
- react = assemble_bit_packed(react,act.targets[i].actions[n].effect,offset+17,offset+21)
- react = assemble_bit_packed(react,act.targets[i].actions[n].stagger,offset+21,offset+24)
- react = assemble_bit_packed(react,act.targets[i].actions[n].knockback,offset+24,offset+27)
- react = assemble_bit_packed(react,act.targets[i].actions[n].param,offset+27,offset+44)
- react = assemble_bit_packed(react,act.targets[i].actions[n].message,offset+44,offset+54)
- react = assemble_bit_packed(react,act.targets[i].actions[n].unknown,offset+54,offset+85)
-
- react = assemble_bit_packed(react,act.targets[i].actions[n].has_add_effect,offset+85,offset+86)
- offset = offset + 86
- if act.targets[i].actions[n].has_add_effect then
- react = assemble_bit_packed(react,act.targets[i].actions[n].add_effect_animation,offset,offset+6)
- react = assemble_bit_packed(react,act.targets[i].actions[n].add_effect_effect,offset+6,offset+10)
- react = assemble_bit_packed(react,act.targets[i].actions[n].add_effect_param,offset+10,offset+27)
- react = assemble_bit_packed(react,act.targets[i].actions[n].add_effect_message,offset+27,offset+37)
- offset = offset + 37
- end
- react = assemble_bit_packed(react,act.targets[i].actions[n].has_spike_effect,offset,offset+1)
- offset = offset + 1
- if act.targets[i].actions[n].has_spike_effect then
- react = assemble_bit_packed(react,act.targets[i].actions[n].spike_effect_animation,offset,offset+6)
- react = assemble_bit_packed(react,act.targets[i].actions[n].spike_effect_effect,offset+6,offset+10)
- react = assemble_bit_packed(react,act.targets[i].actions[n].spike_effect_param,offset+10,offset+24)
- react = assemble_bit_packed(react,act.targets[i].actions[n].spike_effect_message,offset+24,offset+34)
- offset = offset + 34
- end
- end
- end
- if react then
- while #react < #original do
- react = react..original:sub(#react+1,#react+1)
- end
- else
- print('Action Library failure in '..(_addon.name or 'Unknown Addon')..': Invalid Act table returned.')
- end
- return react
-end
-
--- Opens a listener event for the action packet at the incoming chunk level before modifications.
--- Passes in the documented act structures for the original and modified packets.
--- If a table is returned, the library will treat it as a modified act table and recompose the packet string from it.
--- If an invalid act table is passed, it will silently fail to be returned.
-function ActionPacket.open_listener(funct)
- if not funct or type(funct) ~= 'function' then return end
- local id = windower.register_event('incoming chunk',function(id, org, modi, is_injected, is_blocked)
- if id == 0x28 then
- local act_org = windower.packets.parse_action(org)
- act_org.size = org:byte(5)
- local act_mod = windower.packets.parse_action(modi)
- act_mod.size = modi:byte(5)
- return act_to_string(org,funct(act_org,act_mod))
- end
- end)
- return id
-end
-
-function ActionPacket.close_listener(id)
- if not id or type(id) ~= 'number' then return end
- windower.unregister_event(id)
-end
-
-
-local actor_animation_twoCC = {
- wh='White Magic',
- bk='Black Magic',
- bl='Blue Magic',
- sm='Summoning Magic',
- te='TP Move',
- ['k0']='Melee Attack',
- ['lg']='Ranged Attack',
- }
-
-function actionpacket:get_animation_string()
- return actor_animation_twoCC[string.char(actor_animation_twoCC[self.raw['unknown']]%256,math.floor(actor_animation_twoCC[self.raw['unknown']]/256))]
-end
-
-
-function actionpacket:get_category_string()
- return category_strings[self.raw['category']]
-end
-
-function actionpacket:get_spell()
- local info = self:get_targets()():get_actions()():get_basic_info()
- if rawget(info,'resource') and rawget(info,'spell_id') and rawget(rawget(res,rawget(info,'resource')),rawget(info,'spell_id')) then
- local copied_line = {}
- for i,v in pairs(rawget(rawget(res,rawget(info,'resource')),rawget(info,'spell_id'))) do
- rawset(copied_line,i,v)
- end
- setmetatable(copied_line,getmetatable(res[rawget(info,'resource')][rawget(info,'spell_id')]))
- return copied_line
- end
-end
-
--- Returns the name of this actor if there is one
-function actionpacket:get_actor_name()
- local mob = windower.ffxi.get_mob_by_id(self.raw['actor_id'])
-
- if mob then
- return mob['name']
- else
- return nil
- end
-end
-
---Returns the id of the actor
-function actionpacket:get_id()
- return self.raw['actor_id']
-end
-
--- Returns an iterator for this actionpacket's targets
-function actionpacket:get_targets()
- local targets = self.raw['targets']
- local target_count = self.raw['target_count']
- local i = 0
- return function ()
- i = i + 1
- if i <= target_count then
- return Target(self.raw['category'],self.raw['param'],targets[i])
- end
- end
-end
-
-local target = {}
-
--- Constructor for target wrapper
-function Target(category,top_level_param,t)
- if t == nil then
- return
- end
-
- local new_instance = {}
- new_instance.raw = t
- new_instance.category = category
- new_instance.top_level_param = top_level_param
- new_instance.id = t.id
-
- return setmetatable(new_instance, {__index = function (t, k) if rawget(t, k) ~= nil then return t[k] else return target[k] end end})
-end
-
--- Returns an iterator for this target's actions
-function target:get_actions()
- local action_count = self.raw['action_count']
- local i = 0
- return function ()
- i = i + 1
- if i <= action_count then
- return Action(self.category,self.top_level_param,self.raw['actions'][i])
- end
- end
-end
-
--- Returns the name of this target if there is one
-function target:get_name()
- local mob = windower.ffxi.get_mob_by_id(self.raw['id'])
-
- if mob then
- return mob['name']
- else
- return nil
- end
-end
-
-local reaction_strings = {
- [1] = 'evade',
- [2] = 'parry',
- [4] = 'block/guard',
- [8] = 'hit'
- -- 12 = blocked?
- }
-
-local animation_strings = {
- [0] = 'main hand',
- [1] = 'off hand',
- [2] = 'left kick',
- [3] = 'right kick',
- [4] = 'daken throw'
- }
-
-local effect_strings = {
- [2] = 'critical hit'
- }
-
-local stagger_strings = {
- }
-
-local action = {}
-
-function Action(category,top_level_param,t)
- if category == nil or t == nil then
- return
- end
-
- local new_instance = {}
- new_instance.raw = t
- new_instance.raw.category = category_strings[category] or category
- new_instance.raw.top_level_param = top_level_param
-
- return setmetatable(new_instance, {__index = function (t, k) if rawget(t, k) ~= nil then return t[k] else return action[k] or rawget(rawget(t,'raw'),k) end end})
-end
-
-function action:get_basic_info()
- local reaction = self:get_reaction_string()
- local animation = self:get_animation_string()
- local effect = self:get_effect_string()
- local stagger = self:get_stagger_string()
- local message_id = self:get_message_id()
-
- local param, resource, spell_id, interruption, conclusion = self:get_spell()
-
- return {reaction = reaction, animation = animation, effect=effect, message_id = message_id,
- stagger = stagger, param = param, resource = resource, spell_id = spell_id,
- interruption = interruption, conclusion = conclusion}
-end
-
-function action:get_reaction_string()
- local reaction = rawget(rawget(self,'raw'),'reaction')
- return rawget(reaction_strings,reaction) or reaction
-end
-
-function action:get_animation_string()
- local animation = rawget(rawget(self,'raw'),'animation')
- return rawget(animation_strings,animation) or animation
-end
-
-function action:get_effect_string()
- local effect = rawget(rawget(self,'raw'),'effect')
- return rawget(effect_strings,effect) or effect
-end
-
-function action:get_stagger_string()
- local stagger = rawget(rawget(self,'raw'),'stagger')
- return rawget(stagger_strings,stagger) or stagger
-end
-
-local cat_to_res_map = {['weaponskill_finish']='weapon_skills', ['spell_finish']='spells',
- ['item_finish']='items', ['job_ability']='job_abilities', ['weaponskill_begin']='weapon_skills',
- ['casting_begin']='spells', ['item_begin']='items', ['mob_tp_finish']='monster_abilities',
- ['avatar_tp_finish']='job_abilities', ['job_ability_unblinkable']='job_abilities',
- ['job_ability_run']='job_abilities'}
-local begin_categories = {['weaponskill_begin']=true, ['casting_begin']=true, ['item_begin']=true, ['ranged_begin']=true}
-local finish_categories = {['melee']=true,['ranged_finish']=true,['weaponskill_finish']=true, ['spell_finish']=true, ['item_finish']=true,
- ['job_ability']=true, ['mob_tp_finish']=true, ['avatar_tp_finish']=true, ['job_ability_unblinkable']=true,
- ['job_ability_run']=true}
-local msg_id_to_conclusion_map = {
- [26] = {subject="target", verb="gains", objects={"HP","MP"} },
- [31] = {subject="target", verb="loses", objects={"shadows"} },
- [112] = {subject="target", verb="count", objects={"doom"} },
- [120] = {subject="actor", verb="gains", objects={"Gil"} },
- [132] = {subject="target", verb="steals", objects={"HP"} },
- [133] = {subject="actor", verb="steals", objects={"Petra"} },
- [152] = {subject="actor", verb="gains", objects={"MP"} },
- [229] = {subject="target", verb="loses", objects={"HP"} },
- [231] = {subject="actor", verb="loses", objects={"effects"} },
- [530] = {subject="target", verb="count", objects={"petrify"} }, -- Gradual Petrify
- [557] = {subject="actor", verb="gains", objects={"Alexandrite"} }, -- Using a pouch
- [560] = {subject="actor", verb="gains", objects={"FMs"} }, -- No Foot Rise
- [572] = {subject="actor", verb="steals", objects={"ailments"} }, -- Sacrifice
- [585] = {subject="actor", verb="has", objects={"enmity"} }, -- Libra with actor
- [586] = {subject="target", verb="has", objects={"enmity"} }, -- Libra without actor
- [674] = {subject="actor", verb="gains", objects={"items"} }, -- Scavenge
- [730] = {subject="target", verb="has", objects={"TP"} },
- }
-local expandable = {}
-expandable[{1, 2, 67, 77, 110,157,
- 163,185,196,197,223,252,
- 264,265,288,289,290,291,
- 292,293,294,295,296,297,
- 298,299,300,301,302,317,
- 352,353,379,419,522,576,
- 577,648,650,732,767,768}] = {subject="target", verb="loses", objects={"HP"} }
-expandable[{122,167,383}] = {subject="actor", verb="gains", objects={"HP"} }
-expandable[{7, 24, 102,103,238,263,
- 306,318,357,367,373,382,384,
- 385,386,387,388,389,390,391,
- 392,393,394,395,396,397,398,
- 539,587,606,651,769,770}] = {subject="target", verb="gains", objects={"HP"} }
-expandable[{25, 224,276,358,451,588}] = {subject="target", verb="gains", objects={"MP"} }
-expandable[{161,187,227,274,281}] = {subject="actor", verb="steals", objects={"HP"} }
-expandable[{165,226,454,652}] = {subject="actor", verb="steals", objects={"TP"} }
-expandable[{162,225,228,275,366}] = {subject="actor", verb="steals", objects={"MP"} }
-expandable[{362,363}] = {subject="target", verb="loses", objects={"TP"} }
-expandable[{369,403,417}] = {subject="actor", verb="steals", objects={"attributes"} }
-expandable[{370,404,642}] = {subject="actor", verb="steals", objects={"effects"} }
-expandable[{400,570,571,589,607}] = {subject="target", verb="loses", objects={"ailments"} }
-expandable[{401,405,644}] = {subject="target", verb="loses", objects={"effects"} }
-expandable[{409,452,537}] = {subject="target", verb="gains", objects={"TP"} }
-expandable[{519,520,521,591}] = {subject="target", verb="gains", objects={"daze"} }
-expandable[{14, 535}] = {subject="actor", verb="loses", object={"shadows"} }
-expandable[{603,608}] = {subject="target", verb="gains", objects={"TH"} }
-expandable[{33, 44, 536,}] = {subject="actor", verb="loses", objects={"HP"} }
-for ids,tab in pairs(expandable) do
- for _,id in pairs(ids) do
- msg_id_to_conclusion_map[id] = tab
- end
-end
-local function msg_id_to_conclusion(msg_id)
- return rawget(msg_id_to_conclusion_map,msg_id) or false
-end
-
-function action:get_spell()
- local category = rawget(rawget(self,'raw'),'category')
- -- It's far more accurate to filter by the resources line.
-
- local function fieldsearch(message_id)
- if not message_id or not res.action_messages[message_id] or not res.action_messages[message_id].en then return false end
- local fields = {}
- res.action_messages[message_id].en:gsub("${(.-)}", function(a) if a ~= "actor" and a ~= "target" and a ~= 'lb' then rawset(fields,a,true) end end)
- return fields
- end
-
- local message_id = self:get_message_id()
- local fields = fieldsearch(message_id)
- local param = rawget(finish_categories, category) and rawget(rawget(self, 'raw'), 'param')
- local spell_id = rawget(begin_categories, category) and rawget(rawget(self, 'raw'), 'param') or
- rawget(finish_categories, category) and rawget(rawget(self, 'raw'), 'top_level_param')
- local interruption = rawget(begin_categories, category) and rawget(rawget(self, 'raw'), 'top_level_param') == 28787
- if interruption == nil then interruption = false end
-
- local conclusion = msg_id_to_conclusion(message_id)
-
- local resource
- if not fields or message_id == 31 then
- -- If there is no message, assume the resources type based on the category.
- if category == 'weaponskill_begin' and spell_id <= 256 then
- resource = 'weapon_skills'
- elseif category == 'weaponskill_begin' then
- resource = 'monster_abilities'
- else
- resource = rawget(cat_to_res_map,category) or false
- end
- else
- local msgID_to_res_map = {
- [244] = 'job_abilities', -- Mug
- [328] = 'job_abilities', -- BPs that are out of range
- }
- -- If there is a message, interpret the fields.
- resource = msgID_to_res_map[message_id] or fields.spell and 'spells' or
- fields.weapon_skill and spell_id <= 256 and 'weapon_skills' or
- fields.weapon_skill and spell_id > 256 and 'monster_abilities' or
- fields.ability and 'job_abilities' or
- fields.item and 'items' or rawget(cat_to_res_map,category)
- local msgID_to_spell_id_map = {
- [240] = 43, -- Hide
- [241] = 43, -- Hide failing
- [303] = 74, -- Divine Seal
- [304] = 75, -- Elemental Seal
- [305] = 76, -- Trick Attack
- [311] = 79, -- Cover
- }
- spell_id = msgID_to_spell_id_map[message_id] or spell_id
- end
-
- -- param will be a number or false
- -- resource will be a string or false
- -- spell_id will either be a number or false
- -- interruption will be true or false
- -- conclusion will either be a table or false
-
- return param, resource, spell_id, interruption, conclusion
-end
-
-function action:get_message_id()
- local message_id = rawget(rawget(self,'raw'),'message')
- return message_id or 0
-end
-
----------------------------------------- Additional Effects ----------------------------------------
-local add_effect_animation_strings = {}
-
-add_effect_animation_strings['melee'] = {
- [1] = 'enfire',
- [2] = 'enblizzard',
- [3] = 'enaero',
- [4] = 'enstone',
- [5] = 'enthunder',
- [6] = 'enwater',
- [7] = 'enlight',
- [8] = 'endark',
- [12] = 'enblind',
- [14] = 'enpetrify',
- [21] = 'endrain',
- [22] = 'enaspir',
- [23] = 'enhaste',
- }
-
-add_effect_animation_strings['ranged_finish'] = add_effect_animation_strings['melee']
-
-add_effect_animation_strings['weaponskill_finish'] = {
- [1] = 'light',
- [2] = 'darkness',
- [3] = 'gravitation',
- [4] = 'fragmentation',
- [5] = 'distortion',
- [6] = 'fusion',
- [7] = 'compression',
- [8] = 'liquefaction',
- [9] = 'induration',
- [10] = 'reverberation',
- [11] = 'transfixion',
- [12] = 'scission',
- [13] = 'detonation',
- [14] = 'impaction',
- [15] = 'radiance',
- [16] = 'umbra',
- }
-
-add_effect_animation_strings['spell_finish'] = add_effect_animation_strings['weaponskill_finish']
-add_effect_animation_strings['mob_tp_finish'] = add_effect_animation_strings['weaponskill_finish']
-add_effect_animation_strings['avatar_tp_finish'] = add_effect_animation_strings['weaponskill_finish']
-
-local add_effect_effect_strings = {}
-
-function action:get_add_effect()
- if not rawget(rawget(self,'raw'),'has_add_effect') then return false end
- local animation = self:get_add_effect_animation_string()
- local effect = self:get_add_effect_effect_string()
- local param = rawget(rawget(self,'raw'),'add_effect_param')
- local message_id = rawget(rawget(self,'raw'),'add_effect_message')
- local conclusion = msg_id_to_conclusion(message_id)
- return {animation = animation, effect = effect, param = param,
- message_id = message_id,conclusion = conclusion}
-end
-
-function action:get_add_effect_animation_string()
- local add_effect_animation = rawget(rawget(self,'raw'),'add_effect_animation')
- local add_eff_animation_tab = rawget(add_effect_animation_strings,rawget(rawget(self,'raw'),'category'))
- return add_eff_animation_tab and rawget(add_eff_animation_tab,add_effect_animation) or add_effect_animation
-end
-
-function action:get_add_effect_effect_string()
- local add_effect_effect = rawget(rawget(self,'raw'),'add_effect_effect')
- return rawget(add_effect_effect_strings,add_effect_effect) or add_effect_effect
-end
-
-function action:get_add_effect_conclusion()
- return msg_id_to_conclusion(rawget(rawget(self,'raw'),'add_effect_message'))
-end
-
-
-------------------------------------------- Spike Effects ------------------------------------------
-local spike_effect_animation_strings = {
- [1] = 'blaze spikes',
- [2] = 'ice spikes',
- [3] = 'dread spikes',
- [4] = 'water spikes',
- [5] = 'shock spikes',
- [6] = 'reprisal',
- [7] = 'wind spikes',
- [8] = 'stone spikes',
- [63] = 'counter',
- }
-
-local spike_effect_effect_strings = {
- }
-function action:get_spike_effect()
- if not rawget(rawget(self,'raw'),'has_spike_effect') then return false end
- local effect = self:get_spike_effect_effect_string()
- local animation = self:get_spike_effect_animation_string()
- local param = rawget(rawget(self,'raw'),'spike_effect_param')
- local message_id = rawget(rawget(self,'raw'),'spike_effect_message')
- local conclusion = msg_id_to_conclusion(message_id)
- return {animation = animation, effect = effect, param = param,
- message_id = message_id,conclusion = conclusion}
-end
-
-function action:get_spike_effect_effect_string()
- local spike_effect_effect = rawget(rawget(self,'raw'),'spike_effect_effect')
- return rawget(spike_effect_effect_strings,spike_effect_effect) or spike_effect_effect
-end
-
-function action:get_spike_effect_animation_string()
- local spike_effect_animation = rawget(rawget(self,'raw'),'spike_effect_animation')
- return rawget(spike_effect_animation_strings,spike_effect_animation) or spike_effect_animation
-end
-
-function action:get_additional_effect_conclusion()
- return msg_id_to_conclusion(rawget(rawget(self,'raw'),'spike_effect_message'))
-end
-
---[[
-Copyright © 2013, Suji
-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 actions 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 SUJI 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.
-]]