Advertisement
Dakpluto

Tugboat Prelim SMN

Dec 13th, 2016
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 29.53 KB | None | 0 0
  1. -------------------------------------------------------------------------------------------------------------------
  2. -- Setup functions for this job.  Generally should not be modified.
  3. -------------------------------------------------------------------------------------------------------------------
  4.  
  5. -- Also, you'll need the Shortcuts addon to handle the auto-targetting of the custom pact commands.
  6.  
  7. --[[
  8.     Custom commands:
  9.    
  10.     gs c petweather
  11.         Automatically casts the storm appropriate for the current avatar, if possible.
  12.    
  13.     gs c siphon
  14.         Automatically run the process to: dismiss the current avatar; cast appropriate
  15.         weather; summon the appropriate spirit; Elemental Siphon; release the spirit;
  16.         and re-summon the avatar.
  17.        
  18.         Will not cast weather you do not have access to.
  19.         Will not re-summon the avatar if one was not out in the first place.
  20.         Will not release the spirit if it was out before the command was issued.
  21.        
  22.     gs c pact [PactType]
  23.         Attempts to use the indicated pact type for the current avatar.
  24.         PactType can be one of:
  25.             cure
  26.             curaga
  27.             buffOffense
  28.             buffDefense
  29.             buffSpecial
  30.             debuff1
  31.             debuff2
  32.             sleep
  33.             nuke2
  34.             nuke4
  35.             bp70
  36.             bp75 (merits and lvl 75-80 pacts)
  37.             astralflow
  38. --]]
  39.  
  40.  
  41. -- Initialization function for this job file.
  42. function get_sets()
  43.     mote_include_version = 2
  44.  
  45.     -- Load and initialize the include file.
  46.     include('Mote-Include.lua')
  47. end
  48.  
  49. -- Setup vars that are user-independent.  state.Buff vars initialized here will automatically be tracked.
  50. function job_setup()
  51.     state.Buff["Avatar's Favor"] = buffactive["Avatar's Favor"] or false
  52.     state.Buff["Astral Conduit"] = buffactive["Astral Conduit"] or false
  53.  
  54.     spirits = S{"LightSpirit", "DarkSpirit", "FireSpirit", "EarthSpirit", "WaterSpirit", "AirSpirit", "IceSpirit", "ThunderSpirit"}
  55.     avatars = S{"Carbuncle", "Fenrir", "Diabolos", "Ifrit", "Titan", "Leviathan", "Garuda", "Shiva", "Ramuh", "Odin", "Alexander", "Cait Sith"}
  56.  
  57.     magicalRagePacts = S{
  58.         'Inferno','Earthen Fury','Tidal Wave','Aerial Blast','Diamond Dust','Judgment Bolt','Searing Light','Howling Moon','Ruinous Omen',
  59.         'Fire II','Stone II','Water II','Aero II','Blizzard II','Thunder II',
  60.         'Fire IV','Stone IV','Water IV','Aero IV','Blizzard IV','Thunder IV',
  61.         'Thunderspark','Burning Strike','Meteorite','Nether Blast','Flaming Crush',
  62.         'Meteor Strike','Heavenly Strike','Wind Blade','Geocrush','Grand Fall','Thunderstorm',
  63.         'Holy Mist','Lunar Bay','Night Terror','Level ? Holy'}
  64.  
  65.  
  66.     pacts = {}
  67.     pacts.cure = {['Carbuncle']='Healing Ruby'}
  68.     pacts.curaga = {['Carbuncle']='Healing Ruby II', ['Garuda']='Whispering Wind', ['Leviathan']='Spring Water'}
  69.     pacts.buffoffense = {['Carbuncle']='Glittering Ruby', ['Ifrit']='Crimson Howl', ['Garuda']='Hastega', ['Ramuh']='Rolling Thunder',
  70.         ['Fenrir']='Ecliptic Growl'}
  71.     pacts.buffdefense = {['Carbuncle']='Shining Ruby', ['Shiva']='Frost Armor', ['Garuda']='Aerial Armor', ['Titan']='Earthen Ward',
  72.         ['Ramuh']='Lightning Armor', ['Fenrir']='Ecliptic Howl', ['Diabolos']='Noctoshield', ['Cait Sith']='Reraise II'}
  73.     pacts.buffspecial = {['Ifrit']='Inferno Howl', ['Garuda']='Fleet Wind', ['Titan']='Earthen Armor', ['Diabolos']='Dream Shroud',
  74.         ['Carbuncle']='Soothing Ruby', ['Fenrir']='Heavenward Howl', ['Cait Sith']='Raise II'}
  75.     pacts.debuff1 = {['Shiva']='Diamond Storm', ['Ramuh']='Shock Squall', ['Leviathan']='Tidal Roar', ['Fenrir']='Lunar Cry',
  76.         ['Diabolos']='Pavor Nocturnus', ['Cait Sith']='Eerie Eye'}
  77.     pacts.debuff2 = {['Shiva']='Sleepga', ['Leviathan']='Slowga', ['Fenrir']='Lunar Roar', ['Diabolos']='Somnolence'}
  78.     pacts.sleep = {['Shiva']='Sleepga', ['Diabolos']='Nightmare', ['Cait Sith']='Mewing Lullaby'}
  79.     pacts.nuke2 = {['Ifrit']='Fire II', ['Shiva']='Blizzard II', ['Garuda']='Aero II', ['Titan']='Stone II',
  80.         ['Ramuh']='Thunder II', ['Leviathan']='Water II'}
  81.     pacts.nuke4 = {['Ifrit']='Fire IV', ['Shiva']='Blizzard IV', ['Garuda']='Aero IV', ['Titan']='Stone IV',
  82.         ['Ramuh']='Thunder IV', ['Leviathan']='Water IV'}
  83.     pacts.bp70 = {['Ifrit']='Flaming Crush', ['Shiva']='Rush', ['Garuda']='Predator Claws', ['Titan']='Mountain Buster',
  84.         ['Ramuh']='Chaotic Strike', ['Leviathan']='Spinning Dive', ['Carbuncle']='Meteorite', ['Fenrir']='Eclipse Bite',
  85.         ['Diabolos']='Nether Blast',['Cait Sith']='Regal Scratch'}
  86.     pacts.bp75 = {['Ifrit']='Meteor Strike', ['Shiva']='Heavenly Strike', ['Garuda']='Wind Blade', ['Titan']='Geocrush',
  87.         ['Ramuh']='Thunderstorm', ['Leviathan']='Grand Fall', ['Carbuncle']='Holy Mist', ['Fenrir']='Lunar Bay',
  88.         ['Diabolos']='Night Terror', ['Cait Sith']='Level ? Holy'}
  89.     pacts.astralflow = {['Ifrit']='Inferno', ['Shiva']='Diamond Dust', ['Garuda']='Aerial Blast', ['Titan']='Earthen Fury',
  90.         ['Ramuh']='Judgment Bolt', ['Leviathan']='Tidal Wave', ['Carbuncle']='Searing Light', ['Fenrir']='Howling Moon',
  91.         ['Diabolos']='Ruinous Omen', ['Cait Sith']="Altana's Favor"}
  92.  
  93.     -- Wards table for creating custom timers  
  94.     wards = {}
  95.     -- Base duration for ward pacts.
  96.     wards.durations = {
  97.         ['Crimson Howl'] = 60, ['Earthen Armor'] = 60, ['Inferno Howl'] = 60, ['Heavenward Howl'] = 60,
  98.         ['Rolling Thunder'] = 120, ['Fleet Wind'] = 120,
  99.         ['Shining Ruby'] = 180, ['Frost Armor'] = 180, ['Lightning Armor'] = 180, ['Ecliptic Growl'] = 180,
  100.         ['Glittering Ruby'] = 180, ['Hastega'] = 180, ['Noctoshield'] = 180, ['Ecliptic Howl'] = 180,
  101.         ['Dream Shroud'] = 180,
  102.         ['Reraise II'] = 3600
  103.     }
  104.     -- Icons to use when creating the custom timer.
  105.     wards.icons = {
  106.         ['Earthen Armor']   = 'spells/00299.png', -- 00299 for Titan
  107.         ['Shining Ruby']    = 'spells/00043.png', -- 00043 for Protect
  108.         ['Dream Shroud']    = 'spells/00304.png', -- 00304 for Diabolos
  109.         ['Noctoshield']     = 'spells/00106.png', -- 00106 for Phalanx
  110.         ['Inferno Howl']    = 'spells/00298.png', -- 00298 for Ifrit
  111.         ['Hastega']         = 'spells/00358.png', -- 00358 for Hastega
  112.         ['Rolling Thunder'] = 'spells/00104.png', -- 00358 for Enthunder
  113.         ['Frost Armor']     = 'spells/00250.png', -- 00250 for Ice Spikes
  114.         ['Lightning Armor'] = 'spells/00251.png', -- 00251 for Shock Spikes
  115.         ['Reraise II']      = 'spells/00135.png', -- 00135 for Reraise
  116.         ['Fleet Wind']      = 'abilities/00074.png', --
  117.     }
  118.     -- Flags for code to get around the issue of slow skill updates.
  119.     wards.flag = false
  120.     wards.spell = ''
  121.    
  122. end
  123.  
  124. -------------------------------------------------------------------------------------------------------------------
  125. -- User setup functions for this job.  Recommend that these be overridden in a sidecar file.
  126. -------------------------------------------------------------------------------------------------------------------
  127.  
  128. -- Setup vars that are user-dependent.  Can override this function in a sidecar file.
  129. function user_setup()
  130.     state.OffenseMode:options('None', 'Normal', 'Acc')
  131.     state.CastingMode:options('Normal', 'Resistant')
  132.     state.IdleMode:options('Normal', 'PDT')
  133.  
  134.     gear.perp_staff = {name="Chatoyant staff"}
  135.    
  136.     select_default_macro_book()
  137. end
  138.  
  139.  
  140. -- Define sets and vars used by this job file.
  141. function init_gear_sets()
  142.     --------------------------------------
  143.     -- Precast Sets
  144.     --------------------------------------
  145.    
  146.     -- Precast sets to enhance JAs
  147.     sets.precast.JA['Astral Flow'] = {}
  148.    
  149.     sets.precast.JA['Elemental Siphon'] = {main="Soulscourge",
  150.         head="Marduk's tiara",neck="Caller's Pendant",
  151.         body="Caller's Doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  152.         legs="Caller's Spats +2",feet="Caller's Pigaches +2"}
  153.  
  154.     sets.precast.JA['Mana Cede'] = {}
  155.  
  156.     -- Pact delay reduction gear
  157.     sets.precast.BloodPactWard = {main="Soulscourge",
  158.         body="Caller's Doublet +2", back="Tiresias' Cape",legs="Helios spats"}
  159.  
  160.     sets.precast.BloodPactRage = sets.precast.BloodPactWard
  161.  
  162.     -- Fast cast sets for spells
  163.    
  164.     sets.precast.FC = {body="Marduk's Jubbah", ear1="Loquacious Earring"}
  165.  
  166.     sets.precast.FC['Enhancing Magic'] = {waist="Siegel Sash"}
  167.  
  168.  
  169.    
  170.     --------------------------------------
  171.     -- Midcast sets
  172.     --------------------------------------
  173.  
  174.     sets.midcast.FastRecast = {body="Marduk's Jubbah", ear1="Loquacious Earring"}
  175.  
  176.     sets.midcast.Cure = {}
  177.  
  178.     sets.midcast.Stoneskin = {}
  179.    
  180.     sets.midcast.Pet.BloodPactWard = {main="Soulscourge",ammo="Vox Grip",
  181.         head="Marduk's tiara",neck="Caller's Pendant",
  182.         body="Caller's Doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  183.         waist="Diabolos's Rope",legs="Helios spats"}
  184.  
  185.     sets.midcast.Pet.DebuffBloodPactWard = {main="Soulscourge",ammo="Vox Grip",
  186.         head="Marduk's tiara",neck="Caller's Pendant",
  187.         body="Caller's Doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  188.         waist="Diabolos's Rope",legs="Helios spats"}
  189.        
  190.     sets.midcast.Pet.DebuffBloodPactWard.Acc = sets.midcast.Pet.DebuffBloodPactWard
  191.    
  192.     sets.midcast.Pet.PhysicalBloodPactRage = {main="Soulscourge",ammo="Vox Grip",
  193.         head="Marduk's tiara",neck="Caller's Pendant",
  194.         body="Caller's Doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  195.         waist="Diabolos's Rope",legs="Helios spats",back="Tiresias' Cape",ear1="Summoning earring"}
  196.  
  197.     sets.midcast.Pet.PhysicalBloodPactRage.Acc = sets.midcast.Pet.PhysicalBloodPactRage
  198.  
  199.     sets.midcast.Pet.MagicalBloodPactRage = {main="Eminent pole",ammo="Vox Grip",
  200.         head="Marduk's tiara",neck="Eidolon pendant",
  201.         body="Caller's Doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  202.         waist="Diabolos's Rope",legs="Helios spats",back="Tiresias' Cape",ear1="Summoning earring"}
  203.  
  204.     sets.midcast.Pet.MagicalBloodPactRage.Acc = sets.midcast.Pet.MagicalBloodPactRage
  205.  
  206.  
  207.     -- Spirits cast magic spells, which can be identified in standard ways.
  208.    
  209.     sets.midcast.Pet.WhiteMagic = {}
  210.    
  211.     sets.midcast.Pet['Elemental Magic'] = {}
  212.  
  213.     sets.midcast.Pet['Elemental Magic'].Resistant = {}
  214.    
  215.  
  216.     --------------------------------------
  217.     -- Idle/resting/defense/etc sets
  218.     --------------------------------------
  219.    
  220.     -- Resting sets
  221.     sets.resting = {main=gear.Staff.HMP,ammo="Clarus stone",
  222.         head="Goliard chapeau",neck="Eidolon pendant",ear1="Magnetic Earring",ear2="Relaxing Earring",
  223.         body="Mahatma Houppelande",hands="Oracle's Gloves",waist="Austerity Belt",
  224.         legs="Nisse slacks",feet="Avocat Pigaches"}
  225.    
  226.     -- Idle sets
  227.     sets.idle = {main="Chatoyant staff",sub="Vox grip",ammo="Eminent Sachet",
  228.         head="Marduk's tiara",neck="Caller's pendant",ear1="Loquacious Earring",ear2="Caller's Earring",
  229.         body="Marduk's Jubbah",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  230.         back="Astute Cape",waist="Summoning belt",legs="Caller's spats +2",feet="Herald's Gaiters"}
  231.  
  232.     sets.idle.PDT = {main="Chatoyant staff",sub="Vox grip",ammo="Eminent Sachet",
  233.         head="Marduk's tiara",neck="Caller's pendant",ear1="Loquacious Earring",ear2="Caller's Earring",
  234.         body="Marduk's Jubbah",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  235.         back="Astute Cape",waist="Summoning belt",legs="Caller's spats +2",feet="Herald's Gaiters"}
  236.  
  237.     -- perp costs:
  238.     -- spirits: 7
  239.     -- carby: 11 (5 with mitts)
  240.     -- fenrir: 13
  241.     -- others: 15
  242.     -- avatar's favor: -4/tick
  243.    
  244.     -- Max useful -perp gear is 1 less than the perp cost (can't be reduced below 1)
  245.     -- Aim for -14 perp, and refresh in other slots.
  246.    
  247.     -- -perp gear:
  248.     -- Gridarvor: -5
  249.     -- Glyphic Horn: -4
  250.     -- Caller's Doublet +2/Glyphic Doublet: -4
  251.     -- Evoker's Ring: -1
  252.     -- Convoker's Pigaches: -4
  253.     -- total: -18
  254.    
  255.     -- Can make due without either the head or the body, and use +refresh items in those slots.
  256.    
  257.     sets.idle.Avatar = {main="Chatoyant staff",sub="Vox grip",ammo="Eminent Sachet",
  258.         head="Marduk's tiara",neck="Caller's pendant",ear1="Loquacious Earring",ear2="Caller's Earring",
  259.         body="Caller's doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  260.         back="Astute Cape",waist="Summoning belt",legs="Caller's spats +2",feet="Caller's Pigaches +2"}
  261.  
  262.     sets.idle.PDT.Avatar = {main="Chatoyant staff",sub="Vox grip",ammo="Eminent Sachet",
  263.         head="Marduk's tiara",neck="Caller's pendant",ear1="Loquacious Earring",ear2="Caller's Earring",
  264.         body="Caller's doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  265.         back="Astute Cape",waist="Summoning belt",legs="Caller's spats +2",feet="Caller's Pigaches +2"}
  266.  
  267.     sets.idle.Spirit = {main="Chatoyant staff",sub="Vox grip",ammo="Eminent Sachet",
  268.         head="Marduk's tiara",neck="Caller's pendant",ear1="Loquacious Earring",ear2="Caller's Earring",
  269.         body="Caller's doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  270.         back="Astute Cape",waist="Summoning belt",legs="Caller's spats +2",feet="Caller's Pigaches +2"}
  271.  
  272.     sets.idle.Town = {main="Chatoyant staff",sub="Vox grip",ammo="Eminent Sachet",
  273.         head="Marduk's tiara",neck="Caller's pendant",ear1="Loquacious Earring",ear2="Caller's Earring",
  274.         body="Marduk's Jubbah",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  275.         back="Astute Cape",waist="Summoning belt",legs="Caller's spats +2",feet="Herald's Gaiters"}
  276.  
  277.     -- Favor uses Caller's Horn instead of Convoker's Horn for refresh
  278.     sets.idle.Avatar.Favor = {head="Caller's Horn +2"}
  279.     sets.idle.Avatar.Melee = {}
  280.        
  281.     sets.perp = {main="Chatoyant staff",sub="Vox grip",ammo="Eminent Sachet",
  282.         head="Marduk's tiara",neck="Caller's pendant",ear1="Loquacious Earring",ear2="Caller's Earring",
  283.         body="Caller's doublet +2",hands="Psycloth manillas",ring1="Evoker's Ring",ring2="Serket Ring",
  284.         back="Astute Cape",waist="Summoning belt",legs="Caller's spats +2",feet="Caller's Pigaches +2"}
  285.     -- Caller's Bracer's halve the perp cost after other costs are accounted for.
  286.     -- Using -10 (Gridavor, ring, Conv.feet), standard avatars would then cost 5, halved to 2.
  287.     -- We can then use Hagondes Coat and end up with the same net MP cost, but significantly better defense.
  288.     -- Weather is the same, but we can also use the latent on the pendant to negate the last point lost.
  289.     sets.perp.Day = {hands="Caller's Bracers +2"}
  290.     sets.perp.Weather = {neck="Caller's Pendant",hands="Caller's Bracers +2"}
  291.     -- Carby: Mitts+Conv.feet = 1/tick perp.  Everything else should be +refresh
  292.     sets.perp.Carbuncle = {hands="Carbuncle Mitts"}
  293.     sets.perp.Garuda = {head="Karura Hachigane"}
  294.     sets.perp.Diabolos = {waist="Diabolos's Rope"}
  295.     sets.perp.Alexander = sets.midcast.Pet.BloodPactWard
  296.  
  297.     sets.perp.staff_and_grip = {main=gear.perp_staff,sub="Vox Grip"}
  298.     4
  299.     -- Defense sets
  300.     sets.defense.PDT = {}
  301.  
  302.     sets.defense.MDT = {}
  303.  
  304.     sets.Kiting = {feet="Herald's Gaiters"}
  305.    
  306.     sets.latent_refresh = {}
  307.    
  308.  
  309.     --------------------------------------
  310.     -- Engaged sets
  311.     --------------------------------------
  312.    
  313.     -- Normal melee group
  314.     sets.engaged = {}
  315. end
  316.  
  317. -------------------------------------------------------------------------------------------------------------------
  318. -- Job-specific hooks for standard casting events.
  319. -------------------------------------------------------------------------------------------------------------------
  320.  
  321. -- Set eventArgs.handled to true if we don't want any automatic gear equipping to be done.
  322. -- Set eventArgs.useMidcastGear to true if we want midcast gear equipped on precast.
  323. function job_precast(spell, action, spellMap, eventArgs)
  324.     if state.Buff['Astral Conduit'] and pet_midaction() then
  325.         eventArgs.handled = true
  326.     end
  327. end
  328.  
  329. function job_midcast(spell, action, spellMap, eventArgs)
  330.     if state.Buff['Astral Conduit'] and pet_midaction() then
  331.         eventArgs.handled = true
  332.     end
  333. end
  334.  
  335. -- Runs when pet completes an action.
  336. function job_pet_aftercast(spell, action, spellMap, eventArgs)
  337.     if not spell.interrupted and spell.type == 'BloodPactWard' and spellMap ~= 'DebuffBloodPactWard' then
  338.         wards.flag = true
  339.         wards.spell = spell.english
  340.         send_command('wait 4; gs c reset_ward_flag')
  341.     end
  342. end
  343.  
  344. -------------------------------------------------------------------------------------------------------------------
  345. -- Job-specific hooks for non-casting events.
  346. -------------------------------------------------------------------------------------------------------------------
  347.  
  348. -- Called when a player gains or loses a buff.
  349. -- buff == buff gained or lost
  350. -- gain == true if the buff was gained, false if it was lost.
  351. function job_buff_change(buff, gain)
  352.     if state.Buff[buff] ~= nil then
  353.         handle_equipping_gear(player.status)
  354.     elseif storms:contains(buff) then
  355.         handle_equipping_gear(player.status)
  356.     end
  357. end
  358.  
  359.  
  360. -- Called when the player's pet's status changes.
  361. -- This is also called after pet_change after a pet is released.  Check for pet validity.
  362. function job_pet_status_change(newStatus, oldStatus, eventArgs)
  363.     if pet.isvalid and not midaction() and not pet_midaction() and (newStatus == 'Engaged' or oldStatus == 'Engaged') then
  364.         handle_equipping_gear(player.status, newStatus)
  365.     end
  366. end
  367.  
  368.  
  369. -- Called when a player gains or loses a pet.
  370. -- pet == pet structure
  371. -- gain == true if the pet was gained, false if it was lost.
  372. function job_pet_change(petparam, gain)
  373.     classes.CustomIdleGroups:clear()
  374.     if gain then
  375.         if avatars:contains(pet.name) then
  376.             classes.CustomIdleGroups:append('Avatar')
  377.         elseif spirits:contains(pet.name) then
  378.             classes.CustomIdleGroups:append('Spirit')
  379.         end
  380.     else
  381.         select_default_macro_book('reset')
  382.     end
  383. end
  384.  
  385. -------------------------------------------------------------------------------------------------------------------
  386. -- User code that supplements standard library decisions.
  387. -------------------------------------------------------------------------------------------------------------------
  388.  
  389. -- Custom spell mapping.
  390. function job_get_spell_map(spell)
  391.     if spell.type == 'BloodPactRage' then
  392.         if magicalRagePacts:contains(spell.english) then
  393.             return 'MagicalBloodPactRage'
  394.         else
  395.             return 'PhysicalBloodPactRage'
  396.         end
  397.     elseif spell.type == 'BloodPactWard' and spell.target.type == 'MONSTER' then
  398.         return 'DebuffBloodPactWard'
  399.     end
  400. end
  401.  
  402. -- Modify the default idle set after it was constructed.
  403. function customize_idle_set(idleSet)
  404.     if pet.isvalid then
  405.         if pet.element == world.day_element then
  406.             idleSet = set_combine(sets.perp, sets.perp.Day)
  407.         end
  408.         if pet.element == world.weather_element then
  409.             idleSet = set_combine(sets.perp, sets.perp.Weather)
  410.         end
  411.         if sets.perp[pet.name] then
  412.             idleSet = set_combine(sets.perp, sets.perp[pet.name])
  413.         end
  414.         gear.perp_staff.name = elements.perpetuance_staff_of[pet.element]
  415.         if gear.perp_staff.name and (player.inventory[gear.perp_staff.name] or player.wardrobe[gear.perp_staff.name]) then
  416.             idleSet = set_combine(idleSet, sets.perp.staff_and_grip)
  417.         end
  418.         if state.Buff["Avatar's Favor"] and avatars:contains(pet.name) then
  419.             idleSet = set_combine(sets.perp, sets.idle.Avatar.Favor)
  420.         end
  421.         if pet.status == 'Engaged' then
  422.             idleSet = set_combine(sets.perp, sets.idle.Avatar.Melee)
  423.         end
  424.     end
  425.    
  426.     if player.mpp < 51 then
  427.         idleSet = set_combine(sets.perp, sets.latent_refresh)
  428.     end
  429.    
  430.     return idleSet
  431. end
  432.  
  433. -- Called by the 'update' self-command, for common needs.
  434. -- Set eventArgs.handled to true if we don't want automatic equipping of gear.
  435. function job_update(cmdParams, eventArgs)
  436.     classes.CustomIdleGroups:clear()
  437.     if pet.isvalid then
  438.         if avatars:contains(pet.name) then
  439.             classes.CustomIdleGroups:append('Avatar')
  440.         elseif spirits:contains(pet.name) then
  441.             classes.CustomIdleGroups:append('Spirit')
  442.         end
  443.     end
  444. end
  445.  
  446. -- Set eventArgs.handled to true if we don't want the automatic display to be run.
  447. function display_current_job_state(eventArgs)
  448.  
  449. end
  450.  
  451.  
  452. -------------------------------------------------------------------------------------------------------------------
  453. -- User self-commands.
  454. -------------------------------------------------------------------------------------------------------------------
  455.  
  456. -- Called for custom player commands.
  457. function job_self_command(cmdParams, eventArgs)
  458.     if cmdParams[1]:lower() == 'petweather' then
  459.         handle_petweather()
  460.         eventArgs.handled = true
  461.     elseif cmdParams[1]:lower() == 'siphon' then
  462.         handle_siphoning()
  463.         eventArgs.handled = true
  464.     elseif cmdParams[1]:lower() == 'pact' then
  465.         handle_pacts(cmdParams)
  466.         eventArgs.handled = true
  467.     elseif cmdParams[1] == 'reset_ward_flag' then
  468.         wards.flag = false
  469.         wards.spell = ''
  470.         eventArgs.handled = true
  471.     end
  472. end
  473.  
  474.  
  475. -------------------------------------------------------------------------------------------------------------------
  476. -- Utility functions specific to this job.
  477. -------------------------------------------------------------------------------------------------------------------
  478.  
  479. -- Cast the appopriate storm for the currently summoned avatar, if possible.
  480. function handle_petweather()
  481.     if player.sub_job ~= 'SCH' then
  482.         add_to_chat(122, "You can not cast storm spells")
  483.         return
  484.     end
  485.        
  486.     if not pet.isvalid then
  487.         add_to_chat(122, "You do not have an active avatar.")
  488.         return
  489.     end
  490.    
  491.     local element = pet.element
  492.     if element == 'Thunder' then
  493.         element = 'Lightning'
  494.     end
  495.    
  496.     if S{'Light','Dark','Lightning'}:contains(element) then
  497.         add_to_chat(122, 'You do not have access to '..elements.storm_of[element]..'.')
  498.         return
  499.     end
  500.    
  501.     local storm = elements.storm_of[element]
  502.    
  503.     if storm then
  504.         send_command('@input /ma "'..elements.storm_of[element]..'" <me>')
  505.     else
  506.         add_to_chat(123, 'Error: Unknown element ('..tostring(element)..')')
  507.     end
  508. end
  509.  
  510.  
  511. -- Custom uber-handling of Elemental Siphon
  512. function handle_siphoning()
  513.     if areas.Cities:contains(world.area) then
  514.         add_to_chat(122, 'Cannot use Elemental Siphon in a city area.')
  515.         return
  516.     end
  517.  
  518.     local siphonElement
  519.     local stormElementToUse
  520.     local releasedAvatar
  521.     local dontRelease
  522.    
  523.     -- If we already have a spirit out, just use that.
  524.     if pet.isvalid and spirits:contains(pet.name) then
  525.         siphonElement = pet.element
  526.         dontRelease = true
  527.         -- If current weather doesn't match the spirit, but the spirit matches the day, try to cast the storm.
  528.         if player.sub_job == 'SCH' and pet.element == world.day_element and pet.element ~= world.weather_element then
  529.             if not S{'Light','Dark','Lightning'}:contains(pet.element) then
  530.                 stormElementToUse = pet.element
  531.             end
  532.         end
  533.     -- If we're subbing /sch, there are some conditions where we want to make sure specific weather is up.
  534.     -- If current (single) weather is opposed by the current day, we want to change the weather to match
  535.     -- the current day, if possible.
  536.     elseif player.sub_job == 'SCH' and world.weather_element ~= 'None' then
  537.         -- We can override single-intensity weather; leave double weather alone, since even if
  538.         -- it's partially countered by the day, it's not worth changing.
  539.         if get_weather_intensity() == 1 then
  540.             -- If current weather is weak to the current day, it cancels the benefits for
  541.             -- siphon.  Change it to the day's weather if possible (+0 to +20%), or any non-weak
  542.             -- weather if not.
  543.             -- If the current weather matches the current avatar's element (being used to reduce
  544.             -- perpetuation), don't change it; just accept the penalty on Siphon.
  545.             if world.weather_element == elements.weak_to[world.day_element] and
  546.                 (not pet.isvalid or world.weather_element ~= pet.element) then
  547.                 -- We can't cast lightning/dark/light weather, so use a neutral element
  548.                 if S{'Light','Dark','Lightning'}:contains(world.day_element) then
  549.                     stormElementToUse = 'Wind'
  550.                 else
  551.                     stormElementToUse = world.day_element
  552.                 end
  553.             end
  554.         end
  555.     end
  556.    
  557.     -- If we decided to use a storm, set that as the spirit element to cast.
  558.     if stormElementToUse then
  559.         siphonElement = stormElementToUse
  560.     elseif world.weather_element ~= 'None' and (get_weather_intensity() == 2 or world.weather_element ~= elements.weak_to[world.day_element]) then
  561.         siphonElement = world.weather_element
  562.     else
  563.         siphonElement = world.day_element
  564.     end
  565.    
  566.     local command = ''
  567.     local releaseWait = 0
  568.    
  569.     if pet.isvalid and avatars:contains(pet.name) then
  570.         command = command..'input /pet "Release" <me>;wait 1.1;'
  571.         releasedAvatar = pet.name
  572.         releaseWait = 10
  573.     end
  574.    
  575.     if stormElementToUse then
  576.         command = command..'input /ma "'..elements.storm_of[stormElementToUse]..'" <me>;wait 4;'
  577.         releaseWait = releaseWait - 4
  578.     end
  579.    
  580.     if not (pet.isvalid and spirits:contains(pet.name)) then
  581.         command = command..'input /ma "'..elements.spirit_of[siphonElement]..'" <me>;wait 4;'
  582.         releaseWait = releaseWait - 4
  583.     end
  584.    
  585.     command = command..'input /ja "Elemental Siphon" <me>;'
  586.     releaseWait = releaseWait - 1
  587.     releaseWait = releaseWait + 0.1
  588.    
  589.     if not dontRelease then
  590.         if releaseWait > 0 then
  591.             command = command..'wait '..tostring(releaseWait)..';'
  592.         else
  593.             command = command..'wait 1.1;'
  594.         end
  595.        
  596.         command = command..'input /pet "Release" <me>;'
  597.     end
  598.    
  599.     if releasedAvatar then
  600.         command = command..'wait 1.1;input /ma "'..releasedAvatar..'" <me>'
  601.     end
  602.    
  603.     send_command(command)
  604. end
  605.  
  606.  
  607. -- Handles executing blood pacts in a generic, avatar-agnostic way.
  608. -- cmdParams is the split of the self-command.
  609. -- gs c [pact] [pacttype]
  610. function handle_pacts(cmdParams)
  611.     if areas.Cities:contains(world.area) then
  612.         add_to_chat(122, 'You cannot use pacts in town.')
  613.         return
  614.     end
  615.  
  616.     if not pet.isvalid then
  617.         add_to_chat(122,'No avatar currently available. Returning to default macro set.')
  618.         select_default_macro_book('reset')
  619.         return
  620.     end
  621.  
  622.     if spirits:contains(pet.name) then
  623.         add_to_chat(122,'Cannot use pacts with spirits.')
  624.         return
  625.     end
  626.  
  627.     if not cmdParams[2] then
  628.         add_to_chat(123,'No pact type given.')
  629.         return
  630.     end
  631.    
  632.     local pact = cmdParams[2]:lower()
  633.    
  634.     if not pacts[pact] then
  635.         add_to_chat(123,'Unknown pact type: '..tostring(pact))
  636.         return
  637.     end
  638.    
  639.     if pacts[pact][pet.name] then
  640.         if pact == 'astralflow' and not buffactive['astral flow'] then
  641.             add_to_chat(122,'Cannot use Astral Flow pacts at this time.')
  642.             return
  643.         end
  644.        
  645.         -- Leave out target; let Shortcuts auto-determine it.
  646.         send_command('@input /pet "'..pacts[pact][pet.name]..'"')
  647.     else
  648.         add_to_chat(122,pet.name..' does not have a pact of type ['..pact..'].')
  649.     end
  650. end
  651.  
  652.  
  653. -- Event handler for updates to player skill, since we can't rely on skill being
  654. -- correct at pet_aftercast for the creation of custom timers.
  655. windower.raw_register_event('incoming chunk',
  656.     function (id)
  657.         if id == 0x62 then
  658.             if wards.flag then
  659.                 create_pact_timer(wards.spell)
  660.                 wards.flag = false
  661.                 wards.spell = ''
  662.             end
  663.         end
  664.     end)
  665.  
  666. -- Function to create custom timers using the Timers addon.  Calculates ward duration
  667. -- based on player skill and base pact duration (defined in job_setup).
  668. function create_pact_timer(spell_name)
  669.     -- Create custom timers for ward pacts.
  670.     if wards.durations[spell_name] then
  671.         local ward_duration = wards.durations[spell_name]
  672.         if ward_duration < 181 then
  673.             local skill = player.skills.summoning_magic
  674.             if skill > 300 then
  675.                 skill = skill - 300
  676.                 if skill > 200 then skill = 200 end
  677.                 ward_duration = ward_duration + skill
  678.             end
  679.         end
  680.        
  681.         local timer_cmd = 'timers c "'..spell_name..'" '..tostring(ward_duration)..' down'
  682.        
  683.         if wards.icons[spell_name] then
  684.             timer_cmd = timer_cmd..' '..wards.icons[spell_name]
  685.         end
  686.  
  687.         send_command(timer_cmd)
  688.     end
  689. end
  690.  
  691.  
  692. -- Select default macro book on initial load or subjob change.
  693. function select_default_macro_book(reset)
  694.     if reset == 'reset' then
  695.         -- lost pet, or tried to use pact when pet is gone
  696.     end
  697.    
  698.     -- Default macro set/book
  699.     set_macro_page(4, 16)
  700. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement