Advertisement
Lygre

Mote-Utility.lua

Jul 19th, 2016
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 23.39 KB | None | 0 0
  1. -------------------------------------------------------------------------------------------------------------------
  2. -- General utility functions that can be used by any job files.
  3. -- Outside the scope of what the main include file deals with.
  4. -------------------------------------------------------------------------------------------------------------------
  5.  
  6. -------------------------------------------------------------------------------------------------------------------
  7. -- Buff utility functions.
  8. -------------------------------------------------------------------------------------------------------------------
  9.  
  10. local cancel_spells_to_check = S{'Sneak', 'Stoneskin', 'Spectral Jig', 'Trance', 'Monomi: Ichi', 'Utsusemi: Ichi'}
  11. local cancel_types_to_check = S{'Waltz', 'Samba'}
  12.  
  13. -- Function to cancel buffs if they'd conflict with using the spell you're attempting.
  14. -- Requirement: Must have Cancel addon installed and loaded for this to work.
  15. function cancel_conflicting_buffs(spell, action, spellMap, eventArgs)
  16.     if cancel_spells_to_check:contains(spell.english) or cancel_types_to_check:contains(spell.type) then
  17.         if spell.action_type == 'Ability' then
  18.             local abil_recasts = windower.ffxi.get_ability_recasts()
  19.             if abil_recasts[spell.recast_id] > 0 then
  20.                 add_to_chat(123,'Abort: Ability waiting on recast.')
  21.                 eventArgs.cancel = true
  22.                 return
  23.             end
  24.         elseif spell.action_type == 'Magic' then
  25.             local spell_recasts = windower.ffxi.get_spell_recasts()
  26.             if spell_recasts[spell.recast_id] > 0 then
  27.                 add_to_chat(123,'Abort: Spell waiting on recast.')
  28.                 eventArgs.cancel = true
  29.                 return
  30.             end
  31.         end
  32.        
  33.         if spell.english == 'Spectral Jig' and buffactive.sneak then
  34.             cast_delay(0.2)
  35.             send_command('cancel sneak')
  36.         elseif spell.english == 'Sneak' and spell.target.type == 'SELF' and buffactive.sneak then
  37.             send_command('cancel sneak')
  38.         elseif spell.english == ('Stoneskin') then
  39.             send_command('@wait 1.0;cancel stoneskin')
  40.         elseif spell.english:startswith('Monomi') then
  41.             send_command('@wait 1.7;cancel sneak')
  42.         elseif spell.english == 'Utsusemi: Ichi' then
  43.             send_command('@wait 1.7;cancel copy image,copy image (2)')
  44.         elseif (spell.english == 'Trance' or spell.type=='Waltz') and buffactive['saber dance'] then
  45.             cast_delay(0.2)
  46.             send_command('cancel saber dance')
  47.         elseif spell.type=='Samba' and buffactive['fan dance'] then
  48.             cast_delay(0.2)
  49.             send_command('cancel fan dance')
  50.         end
  51.     end
  52. end
  53.  
  54.  
  55. -- Some mythics have special durations for level 1 and 2 aftermaths
  56. local special_aftermath_mythics = S{'Tizona', 'Kenkonken', 'Murgleis', 'Yagrush', 'Carnwenhan', 'Nirvana', 'Tupsimati', 'Idris'}
  57.  
  58. -- Call from job_precast() to setup aftermath information for custom timers.
  59. function custom_aftermath_timers_precast(spell)
  60.     if spell.type == 'WeaponSkill' then
  61.         info.aftermath = {}
  62.        
  63.         local relic_ws = data.weaponskills.relic[player.equipment.main] or data.weaponskills.relic[player.equipment.range]
  64.         local mythic_ws = data.weaponskills.mythic[player.equipment.main] or data.weaponskills.mythic[player.equipment.range]
  65.         local empy_ws = data.weaponskills.empyrean[player.equipment.main] or data.weaponskills.empyrean[player.equipment.range]
  66.        
  67.         if not relic_ws and not mythic_ws and not empy_ws then
  68.             return
  69.         end
  70.  
  71.         info.aftermath.weaponskill = spell.english
  72.         info.aftermath.duration = 0
  73.        
  74.         info.aftermath.level = math.floor(player.tp / 1000)
  75.         if info.aftermath.level == 0 then
  76.             info.aftermath.level = 1
  77.         end
  78.        
  79.         if spell.english == relic_ws then
  80.             info.aftermath.duration = math.floor(0.2 * player.tp)
  81.             if info.aftermath.duration < 20 then
  82.                 info.aftermath.duration = 20
  83.             end
  84.         elseif spell.english == empy_ws then
  85.             -- nothing can overwrite lvl 3
  86.             if buffactive['Aftermath: Lv.3'] then
  87.                 return
  88.             end
  89.             -- only lvl 3 can overwrite lvl 2
  90.             if info.aftermath.level ~= 3 and buffactive['Aftermath: Lv.2'] then
  91.                 return
  92.             end
  93.            
  94.             -- duration is based on aftermath level
  95.             info.aftermath.duration = 30 * info.aftermath.level
  96.         elseif spell.english == mythic_ws then
  97.             -- nothing can overwrite lvl 3
  98.             if buffactive['Aftermath: Lv.3'] then
  99.                 return
  100.             end
  101.             -- only lvl 3 can overwrite lvl 2
  102.             if info.aftermath.level ~= 3 and buffactive['Aftermath: Lv.2'] then
  103.                 return
  104.             end
  105.  
  106.             -- Assume mythic is lvl 80 or higher, for duration
  107.                        
  108.             if info.aftermath.level == 1 then
  109.                 info.aftermath.duration = (special_aftermath_mythics:contains(player.equipment.main) and 270) or 90
  110.             elseif info.aftermath.level == 2 then
  111.                 info.aftermath.duration = (special_aftermath_mythics:contains(player.equipment.main) and 270) or 120
  112.             else
  113.                 info.aftermath.duration = 180
  114.             end
  115.         end
  116.     end
  117. end
  118.  
  119.  
  120. -- Call from job_aftercast() to create the custom aftermath timer.
  121. function custom_aftermath_timers_aftercast(spell)
  122.     if not spell.interrupted and spell.type == 'WeaponSkill' and
  123.        info.aftermath and info.aftermath.weaponskill == spell.english and info.aftermath.duration > 0 then
  124.  
  125.         local aftermath_name = 'Aftermath: Lv.'..tostring(info.aftermath.level)
  126.         send_command('timers d "Aftermath: Lv.1"')
  127.         send_command('timers d "Aftermath: Lv.2"')
  128.         send_command('timers d "Aftermath: Lv.3"')
  129.         send_command('timers c "'..aftermath_name..'" '..tostring(info.aftermath.duration)..' down abilities/00027.png')
  130.  
  131.         info.aftermath = {}
  132.     end
  133. end
  134.  
  135.  
  136. -------------------------------------------------------------------------------------------------------------------
  137. -- Utility functions for changing spells and target types in an automatic manner.
  138. -------------------------------------------------------------------------------------------------------------------
  139.  
  140. --[[ local waltz_tp_cost = {['Curing Waltz'] = 200, ['Curing Waltz II'] = 350, ['Curing Waltz III'] = 500, ['Curing Waltz IV'] = 650, ['Curing Waltz V'] = 800}
  141.  
  142. -- Utility function for automatically adjusting the waltz spell being used to match HP needs and TP limits.
  143. -- Handle spell changes before attempting any precast stuff.
  144. function refine_waltz(spell, action, spellMap, eventArgs)
  145.     if spell.type ~= 'Waltz' then
  146.         return
  147.     end
  148.    
  149.     -- Don't modify anything for Healing Waltz or Divine Waltzes
  150.     if spell.english == "Healing Waltz" or spell.english == "Divine Waltz" or spell.english == "Divine Waltz II" then
  151.         return
  152.     end
  153.  
  154.     local newWaltz = spell.english
  155.     local waltzID
  156.    
  157.     local missingHP
  158.    
  159.     -- If curing ourself, get our exact missing HP
  160.     if spell.target.type == "SELF" then
  161.         missingHP = player.max_hp - player.hp
  162.     -- If curing someone in our alliance, we can estimate their missing HP
  163.     elseif spell.target.isallymember then
  164.         local target = find_player_in_alliance(spell.target.name)
  165.         local est_max_hp = target.hp / (target.hpp/100)
  166.         missingHP = math.floor(est_max_hp - target.hp)
  167.     end
  168.    
  169.     -- If we have an estimated missing HP value, we can adjust the preferred tier used.
  170.     if missingHP ~= nil then
  171.         if player.main_job == 'DNC' then
  172.             if missingHP < 40 and spell.target.name == player.name then
  173.                 -- Not worth curing yourself for so little.
  174.                 -- Don't block when curing others to allow for waking them up.
  175.                 add_to_chat(122,'Full HP!')
  176.                 eventArgs.cancel = true
  177.                 return
  178.             elseif missingHP < 200 then
  179.                 newWaltz = 'Curing Waltz'
  180.                 waltzID = 190
  181.             elseif missingHP < 600 then
  182.                 newWaltz = 'Curing Waltz II'
  183.                 waltzID = 191
  184.             elseif missingHP < 1100 then
  185.                 newWaltz = 'Curing Waltz III'
  186.                 waltzID = 192
  187.             elseif missingHP < 1500 then
  188.                 newWaltz = 'Curing Waltz IV'
  189.                 waltzID = 193
  190.             else
  191.                 newWaltz = 'Curing Waltz V'
  192.                 waltzID = 311
  193.             end
  194.         elseif player.sub_job == 'DNC' then
  195.             if missingHP < 40 and spell.target.name == player.name then
  196.                 -- Not worth curing yourself for so little.
  197.                 -- Don't block when curing others to allow for waking them up.
  198.                 add_to_chat(122,'Full HP!')
  199.                 eventArgs.cancel = true
  200.                 return
  201.             elseif missingHP < 150 then
  202.                 newWaltz = 'Curing Waltz'
  203.                 waltzID = 190
  204.             elseif missingHP < 300 then
  205.                 newWaltz = 'Curing Waltz II'
  206.                 waltzID = 191
  207.             else
  208.                 newWaltz = 'Curing Waltz III'
  209.                 waltzID = 192
  210.             end
  211.         else
  212.             -- Not dnc main or sub; bail out
  213.             return
  214.         end
  215.     end
  216.  
  217.     local tpCost = waltz_tp_cost[newWaltz]
  218.  
  219.     local downgrade
  220.    
  221.     -- Downgrade the spell to what we can afford
  222.     if player.tp < tpCost and not buffactive.trance then
  223.             -- Costs:
  224.             -- Curing Waltz:     200 TP
  225.             -- Curing Waltz II:  350 TP
  226.             -- Curing Waltz III: 500 TP
  227.             -- Curing Waltz IV:  650 TP
  228.             -- Curing Waltz V:   800 TP
  229.             -- Divine Waltz:     400 TP
  230.             -- Divine Waltz II:  800 TP
  231.        
  232.         if player.tp < 200 then
  233.             add_to_chat(122, 'Insufficient TP ['..tostring(player.tp)..']. Cancelling.')
  234.             eventArgs.cancel = true
  235.             return
  236.         elseif player.tp < 350 then
  237.             newWaltz = 'Curing Waltz'
  238.         elseif player.tp < 500 then
  239.             newWaltz = 'Curing Waltz II'
  240.         elseif player.tp < 650 then
  241.             newWaltz = 'Curing Waltz III'
  242.         elseif player.tp < 800 then
  243.             newWaltz = 'Curing Waltz IV'
  244.         end
  245.        
  246.         downgrade = 'Insufficient TP ['..tostring(player.tp)..']. Downgrading to '..newWaltz..'.'
  247.     end
  248.  
  249.    
  250.     if newWaltz ~= spell.english then
  251.         send_command('@input /ja "'..newWaltz..'" '..tostring(spell.target.raw))
  252.         if downgrade then
  253.             add_to_chat(122, downgrade)
  254.         end
  255.         eventArgs.cancel = true
  256.         return
  257.     end
  258.  
  259.     if missingHP and missingHP > 0 then
  260.         add_to_chat(122,'Trying to cure '..tostring(missingHP)..' HP using '..newWaltz..'.')
  261.     end
  262. end
  263. --]]
  264.  
  265. -- Function to allow for automatic adjustment of the spell target type based on preferences.
  266. function auto_change_target(spell, spellMap)
  267.     -- Don't adjust targetting for explicitly named targets
  268.     if not spell.target.raw:startswith('<') then
  269.         return
  270.     end
  271.  
  272.     -- Do not modify target for spells where we get <lastst> or <me>.
  273.     if spell.target.raw == ('<lastst>') or spell.target.raw == ('<me>') then
  274.         return
  275.     end
  276.    
  277.     -- init a new eventArgs with current values
  278.     local eventArgs = {handled = false, PCTargetMode = state.PCTargetMode.value, SelectNPCTargets = state.SelectNPCTargets.value}
  279.  
  280.     -- Allow the job to do custom handling, or override the default values.
  281.     -- They can completely handle it, or set one of the secondary eventArgs vars to selectively
  282.     -- override the default state vars.
  283.     if job_auto_change_target then
  284.         job_auto_change_target(spell, action, spellMap, eventArgs)
  285.     end
  286.    
  287.     -- If the job handled it, we're done.
  288.     if eventArgs.handled then
  289.         return
  290.     end
  291.    
  292.     local pcTargetMode = eventArgs.PCTargetMode
  293.     local selectNPCTargets = eventArgs.SelectNPCTargets
  294.  
  295.    
  296.     local validPlayers = S{'Self', 'Player', 'Party', 'Ally', 'NPC'}
  297.  
  298.     local intersection = spell.targets * validPlayers
  299.     local canUseOnPlayer = not intersection:empty()
  300.    
  301.     local newTarget
  302.    
  303.     -- For spells that we can cast on players:
  304.     if canUseOnPlayer and pcTargetMode ~= 'default' then
  305.         -- Do not adjust targetting for player-targettable spells where the target was <t>
  306.         if spell.target.raw ~= ('<t>') then
  307.             if pcTargetMode == 'stal' then
  308.                 -- Use <stal> if possible, otherwise fall back to <stpt>.
  309.                 if spell.targets.Ally then
  310.                     newTarget = '<stal>'
  311.                 elseif spell.targets.Party then
  312.                     newTarget = '<stpt>'
  313.                 end
  314.             elseif pcTargetMode == 'stpt' then
  315.                 -- Even ally-possible spells are limited to the current party.
  316.                 if spell.targets.Ally or spell.targets.Party then
  317.                     newTarget = '<stpt>'
  318.                 end
  319.             elseif pcTargetMode == 'stpc' then
  320.                 -- If it's anything other than a self-only spell, can change to <stpc>.
  321.                 if spell.targets.Player or spell.targets.Party or spell.targets.Ally or spell.targets.NPC then
  322.                     newTarget = '<stpc>'
  323.                 end
  324.             end
  325.         end
  326.     -- For spells that can be used on enemies:
  327.     elseif spell.targets and spell.targets.Enemy and selectNPCTargets then
  328.         -- Note: this means macros should be written for <t>, and it will change to <stnpc>
  329.         -- if the flag is set.  It won't change <stnpc> back to <t>.
  330.         newTarget = '<stnpc>'
  331.     end
  332.    
  333.     -- If a new target was selected and is different from the original, call the change function.
  334.     if newTarget and newTarget ~= spell.target.raw then
  335.         change_target(newTarget)
  336.     end
  337. end
  338.  
  339.  
  340. -------------------------------------------------------------------------------------------------------------------
  341. -- Environment utility functions.
  342. -------------------------------------------------------------------------------------------------------------------
  343.  
  344. -- Function to get the current weather intensity: 0 for none, 1 for single weather, 2 for double weather.
  345. function get_weather_intensity()
  346.     return gearswap.res.weather[world.weather_id].intensity
  347. end
  348.  
  349.  
  350. -- Returns true if you're in a party solely comprised of Trust NPCs.
  351. -- TODO: Do we need a check to see if we're in a party partly comprised of Trust NPCs?
  352. function is_trust_party()
  353.     -- Check if we're solo
  354.     if party.count == 1 then
  355.         return false
  356.     end
  357.    
  358.     -- Can call a max of 3 Trust NPCs, so parties larger than that are out.
  359.     if party.count > 4 then
  360.         return false
  361.     end
  362.  
  363.     -- If we're in an alliance, can't be a Trust party.
  364.     if alliance[2].count > 0 or alliance[3].count > 0 then
  365.         return false
  366.     end
  367.    
  368.     -- Check that, for each party position aside from our own, the party
  369.     -- member has one of the Trust NPC names, and that those party members
  370.     -- are flagged is_npc.
  371.     for i = 2,4 do
  372.         if party[i] then
  373.             if not npcs.Trust:contains(party[i].name) then
  374.                 return false
  375.             end
  376.             if party[i].mob and party[i].mob.is_npc == false then
  377.                 return false
  378.             end
  379.         end
  380.     end
  381.    
  382.     -- If it didn't fail any of the above checks, return true.
  383.     return true
  384. end
  385.  
  386.  
  387. -- Call these function with a list of equipment slots to check ('head', 'neck', 'body', etc)
  388. -- Returns true if any of the specified slots are currently encumbered.
  389. -- Returns false if all specified slots are unencumbered.
  390. function is_encumbered(...)
  391.     local check_list = {...}
  392.     -- Compensate for people passing a table instead of a series of strings.
  393.     if type(check_list[1]) == 'table' then
  394.         check_list = check_list[1]
  395.     end
  396.     local check_set = S(check_list)
  397.    
  398.     for slot_id,slot_name in pairs(gearswap.default_slot_map) do
  399.         if check_set:contains(slot_name) then
  400.             if gearswap.encumbrance_table[slot_id] then
  401.                 return true
  402.             end
  403.         end
  404.     end
  405.    
  406.     return false
  407. end
  408.  
  409. -------------------------------------------------------------------------------------------------------------------
  410. -- Elemental gear utility functions.
  411. -------------------------------------------------------------------------------------------------------------------
  412.  
  413. -- General handler function to set all the elemental gear for an action.
  414. function set_elemental_gear(spell)
  415.     set_elemental_gorget_belt(spell)
  416.     set_elemental_obi_cape_ring(spell)
  417.     set_elemental_staff(spell)
  418. end
  419.  
  420.  
  421. -- Set the name field of the predefined gear vars for gorgets and belts, for the specified weaponskill.
  422. function set_elemental_gorget_belt(spell)
  423.     if spell.type ~= 'WeaponSkill' then
  424.         return
  425.     end
  426.  
  427.     -- Get the union of all the skillchain elements for the weaponskill
  428.     local weaponskill_elements = S{}:
  429.         union(skillchain_elements[spell.skillchain_a]):
  430.         union(skillchain_elements[spell.skillchain_b]):
  431.         union(skillchain_elements[spell.skillchain_c])
  432.    
  433.     gear.ElementalGorget.name = get_elemental_item_name("gorget", weaponskill_elements) or gear.default.weaponskill_neck  or ""
  434.     gear.ElementalBelt.name   = get_elemental_item_name("belt", weaponskill_elements)   or gear.default.weaponskill_waist or ""
  435. end
  436.  
  437.  
  438. -- Function to get an appropriate obi/cape/ring for the current action.
  439. function set_elemental_obi_cape_ring(spell)
  440.     if spell.element == 'None' then
  441.         return
  442.     end
  443.    
  444.     local world_elements = S{world.day_element}
  445.     if world.weather_element ~= 'None' then
  446.         world_elements:add(world.weather_element)
  447.     end
  448.  
  449.     local obi_name = get_elemental_item_name("obi", S{spell.element}, world_elements)
  450.     gear.ElementalObi.name = obi_name or gear.default.obi_waist  or ""
  451.    
  452.     if obi_name then
  453.         if player.inventory['Twilight Cape'] or player.wardrobe['Twilight Cape'] then
  454.             gear.ElementalCape.name = "Twilight Cape"
  455.         end
  456.         if (player.inventory['Zodiac Ring'] or player.wardrobe['Zodiac Ring']) and spell.english ~= 'Impact' and
  457.             not S{'Divine Magic','Dark Magic','Healing Magic'}:contains(spell.skill) then
  458.             gear.ElementalRing.name = "Zodiac Ring"
  459.         end
  460.     else
  461.         gear.ElementalCape.name = gear.default.obi_back
  462.         gear.ElementalRing.name = gear.default.obi_ring
  463.     end
  464. end
  465.  
  466.  
  467. -- Function to get the appropriate fast cast and/or recast staves for the current spell.
  468. function set_elemental_staff(spell)
  469.     if spell.action_type ~= 'Magic' then
  470.         return
  471.     end
  472.  
  473.     gear.FastcastStaff.name = get_elemental_item_name("fastcast_staff", S{spell.element}) or gear.default.fastcast_staff  or ""
  474.     gear.RecastStaff.name   = get_elemental_item_name("recast_staff", S{spell.element})   or gear.default.recast_staff    or ""
  475. end
  476.  
  477.  
  478. -- Gets the name of an elementally-aligned piece of gear within the player's
  479. -- inventory that matches the conditions set in the parameters.
  480. --
  481. -- item_type: Type of item as specified in the elemental_map mappings.
  482. -- EG: gorget, belt, obi, fastcast_staff, recast_staff
  483. --
  484. -- valid_elements: Elements that are valid for the action being taken.
  485. -- IE: Weaponskill skillchain properties, or spell element.
  486. --
  487. -- restricted_to_elements: Secondary elemental restriction that limits
  488. -- whether the item check can be considered valid.
  489. -- EG: Day or weather elements that have to match the spell element being queried.
  490. --
  491. -- Returns: Nil if no match was found (either due to elemental restrictions,
  492. -- or the gear isn't in the player inventory), or the name of the piece of
  493. -- gear that matches the query.
  494. function get_elemental_item_name(item_type, valid_elements, restricted_to_elements)
  495.     local potential_elements = restricted_to_elements or elements.list
  496.     local item_map = elements[item_type:lower()..'_of']
  497.    
  498.     for element in (potential_elements.it or it)(potential_elements) do
  499.         if valid_elements:contains(element) and (player.inventory[item_map[element]] or player.wardrobe[item_map[element]]) then
  500.             return item_map[element]
  501.         end
  502.     end
  503. end
  504.  
  505.  
  506. -------------------------------------------------------------------------------------------------------------------
  507. -- Function to easily change to a given macro set or book.  Book value is optional.
  508. -------------------------------------------------------------------------------------------------------------------
  509.  
  510. function set_macro_page(set,book)
  511.     if not tonumber(set) then
  512.         add_to_chat(123,'Error setting macro page: Set is not a valid number ('..tostring(set)..').')
  513.         return
  514.     end
  515.     if set < 1 or set > 10 then
  516.         add_to_chat(123,'Error setting macro page: Macro set ('..tostring(set)..') must be between 1 and 10.')
  517.         return
  518.     end
  519.  
  520.     if book then
  521.         if not tonumber(book) then
  522.             add_to_chat(123,'Error setting macro page: book is not a valid number ('..tostring(book)..').')
  523.             return
  524.         end
  525.         if book < 1 or book > 20 then
  526.             add_to_chat(123,'Error setting macro page: Macro book ('..tostring(book)..') must be between 1 and 20.')
  527.             return
  528.         end
  529.         send_command('@input /macro book '..tostring(book)..';wait .1;input /macro set '..tostring(set))
  530.     else
  531.         send_command('@input /macro set '..tostring(set))
  532.     end
  533. end
  534.  
  535.  
  536. -------------------------------------------------------------------------------------------------------------------
  537. -- Utility functions for including local user files.
  538. -------------------------------------------------------------------------------------------------------------------
  539.  
  540. -- Attempt to load user gear files in place of default gear sets.
  541. -- Return true if one exists and was loaded.
  542. function load_sidecar(job)
  543.     if not job then return false end
  544.    
  545.     -- filename format example for user-local files: whm_gear.lua, or playername_whm_gear.lua
  546.     local filenames = {player.name..'_'..job..'_gear.lua', job..'_gear.lua',
  547.         'gear/'..player.name..'_'..job..'_gear.lua', 'gear/'..job..'_gear.lua',
  548.         'gear/'..player.name..'_'..job..'.lua', 'gear/'..job..'.lua'}
  549.     return optional_include(filenames)
  550. end
  551.  
  552. -- Attempt to include user-globals.  Return true if it exists and was loaded.
  553. function load_user_globals()
  554.     local filenames = {player.name..'-globals.lua', 'user-globals.lua'}
  555.     return optional_include(filenames)
  556. end
  557.  
  558. -- Optional version of include().  If file does not exist, does not
  559. -- attempt to load, and does not throw an error.
  560. -- filenames takes an array of possible file names to include and checks
  561. -- each one.
  562. function optional_include(filenames)
  563.     for _,v in pairs(filenames) do
  564.         local path = gearswap.pathsearch({v})
  565.         if path then
  566.             include(v)
  567.             return true
  568.         end
  569.     end
  570. end
  571.  
  572. -------------------------------------------------------------------------------------------------------------------
  573. -- Utility functions for vars or other data manipulation.
  574. -------------------------------------------------------------------------------------------------------------------
  575.  
  576. -- Attempt to locate a specified name within the current alliance.
  577. function find_player_in_alliance(name)
  578.     for party_index,ally_party in ipairs(alliance) do
  579.         for player_index,_player in ipairs(ally_party) do
  580.             if _player.name == name then
  581.                 return _player
  582.             end
  583.         end
  584.     end
  585. end
  586.  
  587.  
  588. -- buff_set is a set of buffs in a library table (any of S{}, T{} or L{}).
  589. -- This function checks if any of those buffs are present on the player.
  590. function has_any_buff_of(buff_set)
  591.     return buff_set:any(
  592.         -- Returns true if any buff from buff set that is sent to this function returns true:
  593.         function (b) return buffactive[b] end
  594.     )
  595. end
  596.  
  597.  
  598. -- Invert a table such that the keys are values and the values are keys.
  599. -- Use this to look up the index value of a given entry.
  600. function invert_table(t)
  601.     if t == nil then error('Attempting to invert table, received nil.', 2) end
  602.    
  603.     local i={}
  604.     for k,v in pairs(t) do
  605.         i[v] = k
  606.     end
  607.     return i
  608. end
  609.  
  610.  
  611. -- Gets sub-tables based on baseSet from the string str that may be in dot form
  612. -- (eg: baseSet=sets, str='precast.FC', this returns the table sets.precast.FC).
  613. function get_expanded_set(baseSet, str)
  614.     local cur = baseSet
  615.     for i in str:gmatch("[^.]+") do
  616.         if cur then
  617.             cur = cur[i]
  618.         end
  619.     end
  620.    
  621.     return cur
  622. end
  623.  
  624.  
  625. -------------------------------------------------------------------------------------------------------------------
  626. -- Utility functions data and event tracking.
  627. -------------------------------------------------------------------------------------------------------------------
  628.  
  629. -- This is a function that can be attached to a registered event for 'time change'.
  630. -- It will send a call to the update() function if the time period changes.
  631. -- It will also call job_time_change when any of the specific time class values have changed.
  632. -- To activate this in your job lua, add this line to your user_setup function:
  633. -- windower.register_event('time change', time_change)
  634. --
  635. -- Variables it sets: classes.Daytime, and classes.DuskToDawn.  They are set to true
  636. -- if their respective descriptors are true, or false otherwise.
  637. function time_change(new_time, old_time)
  638.     local was_daytime = classes.Daytime
  639.     local was_dusktime = classes.DuskToDawn
  640.    
  641.     if new_time >= 6*60 and new_time < 18*60 then
  642.         classes.Daytime = true
  643.     else
  644.         classes.Daytime = false
  645.     end
  646.  
  647.     if new_time >= 17*60 or new_time < 7*60 then
  648.         classes.DuskToDawn = true
  649.     else
  650.         classes.DuskToDawn = false
  651.     end
  652.    
  653.     if was_daytime ~= classes.Daytime or was_dusktime ~= classes.DuskToDawn then
  654.         if job_time_change then
  655.             job_time_change(new_time, old_time)
  656.         end
  657.  
  658.         handle_update({'auto'})
  659.     end
  660. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement