Advertisement
bongarippa

Mote-Utility_lua

Jul 27th, 2014
239
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.10 KB | None | 0 0
  1. -------------------------------------------------------------------------------------------------------------------
  2. -- General utility functions that can be used by any job files. Outside the scope of what the main
  3. -- include file deals with.
  4. -------------------------------------------------------------------------------------------------------------------
  5.  
  6. -------------------------------------------------------------------------------------------------------------------
  7. -- Buff-cancelling utility functions.
  8. -------------------------------------------------------------------------------------------------------------------
  9.  
  10. local cancel_spells_to_check = S{'Sneak', '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.5;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*')
  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. -------------------------------------------------------------------------------------------------------------------
  56. -- Utility functions for changing spells and target types in an automatic manner.
  57. -------------------------------------------------------------------------------------------------------------------
  58.  
  59. local waltz_tp_cost = {['Curing Waltz'] = 20, ['Curing Waltz II'] = 35, ['Curing Waltz III'] = 50, ['Curing Waltz IV'] = 65, ['Curing Waltz V'] = 80}
  60.  
  61. -- Utility function for automatically adjusting the waltz spell being used to match HP needs and TP limits.
  62. -- Handle spell changes before attempting any precast stuff.
  63. function refine_waltz(spell, action, spellMap, eventArgs)
  64. if spell.type ~= 'Waltz' then
  65. return
  66. end
  67.  
  68. -- Don't modify anything for Healing Waltz or Divine Waltzes
  69. if spell.english == "Healing Waltz" or spell.english == "Divine Waltz" or spell.english == "Divine Waltz II" then
  70. return
  71. end
  72.  
  73. local newWaltz = spell.english
  74. local waltzID
  75.  
  76. local missingHP
  77.  
  78. -- If curing ourself, get our exact missing HP
  79. if spell.target.type == "SELF" then
  80. missingHP = player.max_hp - player.hp
  81. -- If curing someone in our alliance, we can estimate their missing HP
  82. elseif spell.target.isallymember then
  83. local target = find_player_in_alliance(spell.target.name)
  84. local est_max_hp = target.hp / (target.hpp/100)
  85. missingHP = math.floor(est_max_hp - target.hp)
  86. end
  87.  
  88. -- If we have an estimated missing HP value, we can adjust the preferred tier used.
  89. if missingHP ~= nil then
  90. if player.main_job == 'DNC' then
  91. if missingHP < 40 and spell.target.name == player.name then
  92. -- Not worth curing yourself for so little.
  93. -- Don't block when curing others to allow for waking them up.
  94. add_to_chat(122,'Full HP!')
  95. eventArgs.cancel = true
  96. return
  97. elseif missingHP < 200 then
  98. newWaltz = 'Curing Waltz'
  99. waltzID = 190
  100. elseif missingHP < 600 then
  101. newWaltz = 'Curing Waltz II'
  102. waltzID = 191
  103. elseif missingHP < 1100 then
  104. newWaltz = 'Curing Waltz III'
  105. waltzID = 192
  106. elseif missingHP < 1500 then
  107. newWaltz = 'Curing Waltz IV'
  108. waltzID = 193
  109. else
  110. newWaltz = 'Curing Waltz V'
  111. waltzID = 311
  112. end
  113. elseif player.sub_job == 'DNC' then
  114. if missingHP < 40 and spell.target.name == player.name then
  115. -- Not worth curing yourself for so little.
  116. -- Don't block when curing others to allow for waking them up.
  117. add_to_chat(122,'Full HP!')
  118. eventArgs.cancel = true
  119. return
  120. elseif missingHP < 150 then
  121. newWaltz = 'Curing Waltz'
  122. waltzID = 190
  123. elseif missingHP < 300 then
  124. newWaltz = 'Curing Waltz II'
  125. waltzID = 191
  126. else
  127. newWaltz = 'Curing Waltz III'
  128. waltzID = 192
  129. end
  130. else
  131. -- Not dnc main or sub; bail out
  132. return
  133. end
  134. end
  135.  
  136. local tpCost = waltz_tp_cost[newWaltz]
  137.  
  138. local downgrade
  139.  
  140. -- Downgrade the spell to what we can afford
  141. if player.tp < tpCost and not buffactive.trance then
  142. --[[ Costs:
  143. Curing Waltz: 20 TP
  144. Curing Waltz II: 35 TP
  145. Curing Waltz III: 50 TP
  146. Curing Waltz IV: 65 TP
  147. Curing Waltz V: 80 TP
  148. Divine Waltz: 40 TP
  149. Divine Waltz II: 80 TP
  150. --]]
  151.  
  152. if player.tp < 20 then
  153. add_to_chat(122, 'Insufficient TP ['..tostring(player.tp)..']. Cancelling.')
  154. eventArgs.cancel = true
  155. return
  156. elseif player.tp < 35 then
  157. newWaltz = 'Curing Waltz'
  158. elseif player.tp < 50 then
  159. newWaltz = 'Curing Waltz II'
  160. elseif player.tp < 65 then
  161. newWaltz = 'Curing Waltz III'
  162. elseif player.tp < 80 then
  163. newWaltz = 'Curing Waltz IV'
  164. end
  165.  
  166. downgrade = 'Insufficient TP ['..tostring(player.tp)..']. Downgrading to '..newWaltz..'.'
  167. end
  168.  
  169.  
  170. if newWaltz ~= spell.english then
  171. send_command('@input /ja "'..newWaltz..'" '..tostring(spell.target.raw))
  172. if downgrade then
  173. add_to_chat(122, downgrade)
  174. end
  175. eventArgs.cancel = true
  176. return
  177. end
  178.  
  179. if missingHP > 0 then
  180. add_to_chat(122,'Trying to cure '..tostring(missingHP)..' HP using '..newWaltz..'.')
  181. end
  182. end
  183.  
  184.  
  185. -- Function to allow for automatic adjustment of the spell target type based on preferences.
  186. function auto_change_target(spell, action, spellMap)
  187. -- Don't adjust targetting for explicitly named targets
  188. if not spell.target.raw:startswith('<') then
  189. return
  190. end
  191.  
  192. -- Do not modify target for spells where we get <lastst> or <me>.
  193. if spell.target.raw == ('<lastst>') or spell.target.raw == ('<me>') then
  194. return
  195. end
  196.  
  197. -- init a new eventArgs with current values
  198. local eventArgs = {handled = false, PCTargetMode = state.PCTargetMode, SelectNPCTargets = state.SelectNPCTargets}
  199.  
  200. -- Allow the job to do custom handling, or override the default values.
  201. -- They can completely handle it, or set one of the secondary eventArgs vars to selectively
  202. -- override the default state vars.
  203. if job_auto_change_target then
  204. job_auto_change_target(spell, action, spellMap, eventArgs)
  205. end
  206.  
  207. -- If the job handled it, we're done.
  208. if eventArgs.handled then
  209. return
  210. end
  211.  
  212. local pcTargetMode = eventArgs.PCTargetMode
  213. local selectNPCTargets = eventArgs.SelectNPCTargets
  214.  
  215.  
  216. local validPlayers = S{'Self', 'Player', 'Party', 'Ally', 'NPC'}
  217.  
  218. local intersection = spell.targets * validPlayers
  219. local canUseOnPlayer = not intersection:empty()
  220.  
  221. local newTarget
  222.  
  223. -- For spells that we can cast on players:
  224. if canUseOnPlayer and pcTargetMode ~= 'default' then
  225. -- Do not adjust targetting for player-targettable spells where the target was <t>
  226. if spell.target.raw ~= ('<t>') then
  227. if pcTargetMode == 'stal' then
  228. -- Use <stal> if possible, otherwise fall back to <stpt>.
  229. if spell.targets.Ally then
  230. newTarget = '<stal>'
  231. elseif spell.targets.Party then
  232. newTarget = '<stpt>'
  233. end
  234. elseif pcTargetMode == 'stpt' then
  235. -- Even ally-possible spells are limited to the current party.
  236. if spell.targets.Ally or spell.targets.Party then
  237. newTarget = '<stpt>'
  238. end
  239. elseif pcTargetMode == 'stpc' then
  240. -- If it's anything other than a self-only spell, can change to <stpc>.
  241. if spell.targets.Player or spell.targets.Party or spell.targets.Ally or spell.targets.NPC then
  242. newTarget = '<stpc>'
  243. end
  244. end
  245. end
  246. -- For spells that can be used on enemies:
  247. elseif spell.targets and spell.targets.Enemy and selectNPCTargets then
  248. -- Note: this means macros should be written for <t>, and it will change to <stnpc>
  249. -- if the flag is set. It won't change <stnpc> back to <t>.
  250. newTarget = '<stnpc>'
  251. end
  252.  
  253. -- If a new target was selected and is different from the original, call the change function.
  254. if newTarget and newTarget ~= spell.target.raw then
  255. change_target(newTarget)
  256. end
  257. end
  258.  
  259.  
  260. -------------------------------------------------------------------------------------------------------------------
  261. -- Environment utility functions.
  262. -------------------------------------------------------------------------------------------------------------------
  263.  
  264. -- Function to get the current weather intensity: 0 for none, 1 for single weather, 2 for double weather.
  265. function get_weather_intensity()
  266. if world.weather_id <= 3 then
  267. return 0
  268. else
  269. return (world.weather_id % 2) + 1
  270. end
  271. end
  272.  
  273.  
  274. function is_trust_party()
  275. -- Check if we're solo
  276. if party.count == 1 then
  277. return false
  278. end
  279.  
  280. -- Can call a max of 3 Trust NPCs, so parties larger than that are out.
  281. if party.count > 4 then
  282. return false
  283. end
  284.  
  285. -- If we're in an alliance, can't be a Trust party.
  286. if alliance[2].count > 0 or alliance[3].count > 0 then
  287. return false
  288. end
  289.  
  290. -- Check that, for each party position aside from our own, the party
  291. -- member has one of the Trust NPC names, and that those party members
  292. -- are flagged is_npc.
  293. for i = 2,4 do
  294. if party[i] then
  295. if not npcs.Trust:contains(party[i].name) then
  296. return false
  297. end
  298. if party[i].mob and party[i].mob.is_npc == false then
  299. return false
  300. end
  301. end
  302. end
  303.  
  304. -- If it didn't fail any of the above checks, return true.
  305. return true
  306. end
  307.  
  308.  
  309. -------------------------------------------------------------------------------------------------------------------
  310. -- Elemental gear utility functions.
  311. -------------------------------------------------------------------------------------------------------------------
  312.  
  313. -- General handler function to set all the elemental gear for an action.
  314. function set_elemental_gear(spell)
  315. set_elemental_gorget_belt(spell)
  316. set_elemental_obi_cape_ring(spell)
  317. set_elemental_staff(spell)
  318. end
  319.  
  320.  
  321. -- Set the name field of the predefined gear vars for gorgets and belts, for the specified weaponskill.
  322. function set_elemental_gorget_belt(spell)
  323. if spell.type ~= 'WeaponSkill' then
  324. return
  325. end
  326.  
  327. -- Get the union of all the skillchain elements for the weaponskill
  328. local weaponskill_elements = S{}:
  329. union(skillchain_elements[spell.skillchain_a]):
  330. union(skillchain_elements[spell.skillchain_b]):
  331. union(skillchain_elements[spell.skillchain_c])
  332.  
  333. gear.ElementalGorget.name = get_elemental_item_name("gorget", weaponskill_elements) or gear.default.weaponskill_neck or ""
  334. gear.ElementalBelt.name = get_elemental_item_name("belt", weaponskill_elements) or gear.default.weaponskill_waist or ""
  335. end
  336.  
  337.  
  338. -- Function to get an appropriate obi/cape/ring for the current action.
  339. function set_elemental_obi_cape_ring(spell)
  340. if spell.element == 'None' then
  341. return
  342. end
  343.  
  344. local world_elements = S{world.day_element}
  345. if world.weather_element ~= 'None' then
  346. world_elements:add(world.weather_element)
  347. end
  348.  
  349. local obi_name = get_elemental_item_name("obi", S{spell.element}, world_elements)
  350. gear.ElementalObi.name = obi_name or gear.default.obi_waist or ""
  351.  
  352. if obi_name then
  353. if player.inventory['Twilight Cape'] or player.wardrobe['Twilight Cape'] then
  354. gear.ElementalCape.name = "Twilight Cape"
  355. end
  356. if (player.inventory['Zodiac Ring'] or player.wardrobe['Zodiac Ring']) and spell.english ~= 'Impact' and
  357. not S{'Divine Magic','Dark Magic','Healing Magic'}:contains(spell.skill) then
  358. gear.ElementalRing.name = "Zodiac Ring"
  359. end
  360. else
  361. gear.ElementalCape.name = gear.default.obi_back
  362. gear.ElementalRing.name = gear.default.obi_ring
  363. end
  364. end
  365.  
  366.  
  367. -- Function to get the appropriate fast cast and/or recast staves for the current spell.
  368. function set_elemental_staff(spell)
  369. if spell.action_type ~= 'Magic' then
  370. return
  371. end
  372.  
  373. gear.FastcastStaff.name = get_elemental_item_name("fastcast_staff", S{spell.element}) or gear.default.fastcast_staff or ""
  374. gear.RecastStaff.name = get_elemental_item_name("recast_staff", S{spell.element}) or gear.default.recast_staff or ""
  375. end
  376.  
  377.  
  378. -- Gets the name of an elementally-aligned piece of gear within the player's
  379. -- inventory that matches the conditions set in the parameters.
  380. --
  381. -- item_type: Type of item as specified in the elemental_map mappings.
  382. -- EG: gorget, belt, obi, fastcast_staff, recast_staff
  383. --
  384. -- valid_elements: Elements that are valid for the action being taken.
  385. -- IE: Weaponskill skillchain properties, or spell element.
  386. --
  387. -- restricted_to_elements: Secondary elemental restriction that limits
  388. -- whether the item check can be considered valid.
  389. -- EG: Day or weather elements that have to match the spell element being queried.
  390. --
  391. -- Returns: Nil if no match was found (either due to elemental restrictions,
  392. -- or the gear isn't in the player inventory), or the name of the piece of
  393. -- gear that matches the query.
  394. function get_elemental_item_name(item_type, valid_elements, restricted_to_elements)
  395. local potential_elements = restricted_to_elements or elements.list
  396. local item_map = elements[item_type:lower()..'_of']
  397.  
  398. for element in (potential_elements.it or it)(potential_elements) do
  399. if valid_elements:contains(element) and (player.inventory[item_map[element]] or player.wardrobe[item_map[element]]) then
  400. return item_map[element]
  401. end
  402. end
  403. end
  404.  
  405.  
  406. -------------------------------------------------------------------------------------------------------------------
  407. -- Function to easily change to a given macro set or book. Book value is optional.
  408. -------------------------------------------------------------------------------------------------------------------
  409.  
  410. function set_macro_page(set,book)
  411. if not tonumber(set) then
  412. add_to_chat(123,'Error setting macro page: Set is not a valid number ('..tostring(set)..').')
  413. return
  414. end
  415. if set < 1 or set > 10 then
  416. add_to_chat(123,'Error setting macro page: Macro set ('..tostring(set)..') must be between 1 and 10.')
  417. return
  418. end
  419.  
  420. if book then
  421. if not tonumber(book) then
  422. add_to_chat(123,'Error setting macro page: book is not a valid number ('..tostring(book)..').')
  423. return
  424. end
  425. if book < 1 or book > 20 then
  426. add_to_chat(123,'Error setting macro page: Macro book ('..tostring(book)..') must be between 1 and 20.')
  427. return
  428. end
  429. send_command('@input /macro book '..tostring(book)..';wait .1;input /macro set '..tostring(set))
  430. else
  431. send_command('@input /macro set '..tostring(set))
  432. end
  433. end
  434.  
  435.  
  436. -------------------------------------------------------------------------------------------------------------------
  437. -- Utility functions for including local user files.
  438. -------------------------------------------------------------------------------------------------------------------
  439.  
  440. -- Attempt to load user gear files in place of default gear sets.
  441. -- Return true if one exists and was loaded.
  442. function load_user_gear(job)
  443. if not job then return false end
  444.  
  445. -- filename format example for user-local files: whm_gear.lua, or playername_whm_gear.lua
  446. local filenames = {player.name..'_'..job..'_gear.lua', job..'_gear.lua'}
  447. return optional_include(filenames)
  448. end
  449.  
  450. -- Attempt to include user-globals. Return true if it exists and was loaded.
  451. function load_user_globals()
  452. local filenames = {player.name..'-globals.lua', 'user-globals.lua'}
  453. return optional_include(filenames)
  454. end
  455.  
  456. -- Optional version of include(). If file does not exist, does not
  457. -- attempt to load, and does not throw an error.
  458. -- filenames takes an array of possible file names to include and checks
  459. -- each one.
  460. function optional_include(filenames)
  461. for _,v in pairs(filenames) do
  462. local path = gearswap.pathsearch({v})
  463. if path then
  464. include(v)
  465. return true
  466. end
  467. end
  468. end
  469.  
  470. -------------------------------------------------------------------------------------------------------------------
  471. -- Utility functions for vars or other data manipulation.
  472. -------------------------------------------------------------------------------------------------------------------
  473.  
  474. -- Attempt to locate a specified name within the current alliance.
  475. function find_player_in_alliance(name)
  476. for party_index,ally_party in ipairs(alliance) do
  477. for player_index,_player in ipairs(ally_party) do
  478. if _player.name == name then
  479. return _player
  480. end
  481. end
  482. end
  483. end
  484.  
  485.  
  486. -- buff_set is a set of buffs in a library table (any of S{}, T{} or L{}).
  487. -- This function checks if any of those buffs are present on the player.
  488. function has_any_buff_of(buff_set)
  489. return buff_set:any(
  490. -- Returns true if any buff from buff set that is sent to this function returns true:
  491. function (b) return buffactive[b] end
  492. )
  493. end
  494.  
  495.  
  496. -- Invert a table such that the keys are values and the values are keys.
  497. -- Use this to look up the index value of a given entry.
  498. function invert_table(t)
  499. if t == nil then error('Attempting to invert table, received nil.', 2) end
  500.  
  501. local i={}
  502. for k,v in pairs(t) do
  503. i[v] = k
  504. end
  505. return i
  506. end
  507.  
  508.  
  509. -- Gets sub-tables based on baseSet from the string str that may be in dot form
  510. -- (eg: baseSet=sets, str='precast.FC', this returns the table sets.precast.FC).
  511. function get_expanded_set(baseSet, str)
  512. local cur = baseSet
  513. for i in str:gmatch("[^.]+") do
  514. if cur then
  515. cur = cur[i]
  516. end
  517. end
  518.  
  519. return cur
  520. end
  521.  
  522.  
  523. -------------------------------------------------------------------------------------------------------------------
  524. -- Utility functions data and event tracking.
  525. -------------------------------------------------------------------------------------------------------------------
  526.  
  527. -- This is a function that can be attached to a registered event for 'time change'.
  528. -- It will send a call to the update() function if the time period changes.
  529. function time_change(new_time, old_time)
  530. local was_daytime = classes.Daytime
  531. local was_dusktime = classes.DuskToDawn
  532.  
  533. if new_time >= 6*60 and new_time < 18*60 then
  534. classes.Daytime = true
  535. else
  536. classes.Daytime = false
  537. end
  538.  
  539. if new_time >= 17*60 or new_time < 7*60 then
  540. classes.DuskToDawn = true
  541. else
  542. classes.DuskToDawn = false
  543. end
  544.  
  545. if was_daytime ~= classes.Daytime or was_dusktime ~= classes.DuskToDawn then
  546. if job_time_change then
  547. job_time_change(new_time, old_time)
  548. end
  549.  
  550. handle_update({'auto'})
  551. end
  552. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement