summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/rev1/Mote-Include.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/rev1/Mote-Include.lua')
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/rev1/Mote-Include.lua1125
1 files changed, 1125 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/rev1/Mote-Include.lua b/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/rev1/Mote-Include.lua
new file mode 100644
index 0000000..6ab1614
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/libs/rev1/Mote-Include.lua
@@ -0,0 +1,1125 @@
+-------------------------------------------------------------------------------------------------------------------
+-- Common variables and functions to be included in job scripts, for general default handling.
+--
+-- Include this file in the get_sets() function with the command:
+-- include('Mote-Include.lua')
+--
+-- It will then automatically run its own init_include() function.
+--
+-- IMPORTANT: This include requires supporting include files:
+-- Mote-Utility
+-- Mote-Mappings
+-- Mote-SelfCommands
+-- Mote-Globals
+--
+-- Place the include() directive at the start of a job's get_sets() function.
+--
+-- Included variables and functions are considered to be at the same scope level as
+-- the job script itself, and can be used as such.
+-------------------------------------------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------------------------------------------
+-- Initialization function that defines variables to be used.
+-- These are accessible at the including job lua script's scope.
+--
+-- Auto-initialize after defining this function.
+-------------------------------------------------------------------------------------------------------------------
+
+
+function init_include()
+ -- Used to define various types of data mappings. These may be used in the initialization,
+ -- so load it up front.
+ include('Mote-Mappings')
+
+ -- Var for tracking misc info
+ info = {}
+
+ -- Var for tracking state values
+ state = {}
+
+ -- General melee offense/defense modes, allowing for hybrid set builds, as well as idle/resting/weaponskill.
+ state.OffenseMode = 'Normal'
+ state.DefenseMode = 'Normal'
+ state.RangedMode = 'Normal'
+ state.WeaponskillMode = 'Normal'
+ state.CastingMode = 'Normal'
+ state.IdleMode = 'Normal'
+ state.RestingMode = 'Normal'
+
+ -- All-out defense state, either physical or magical
+ state.Defense = {}
+ state.Defense.Active = false
+ state.Defense.Type = 'Physical'
+ state.Defense.PhysicalMode = 'PDT'
+ state.Defense.MagicalMode = 'MDT'
+
+ state.Kiting = false
+ state.MaxWeaponskillDistance = 0
+
+ state.SelectNPCTargets = false
+ state.PCTargetMode = 'default'
+
+ state.CombatWeapon = nil
+ state.CombatForm = nil
+
+ state.Buff = {}
+
+
+ -- Vars for specifying valid mode values.
+ -- Defaults here are just for example. Set them properly in each job file.
+ options = {}
+ options.OffenseModes = {'Normal'}
+ options.DefenseModes = {'Normal'}
+ options.RangedModes = {'Normal'}
+ options.WeaponskillModes = {'Normal'}
+ options.CastingModes = {'Normal'}
+ options.IdleModes = {'Normal'}
+ options.RestingModes = {'Normal'}
+ options.PhysicalDefenseModes = {'PDT'}
+ options.MagicalDefenseModes = {'MDT'}
+
+ options.TargetModes = {'default', 'stpc', 'stpt', 'stal'}
+
+
+ -- Spell mappings to describe a 'type' of spell. Used when searching for valid sets.
+ classes = {}
+ -- Basic spell mappings are based on common spell series.
+ -- EG: 'Cure' for Cure, Cure II, Cure III, Cure IV, Cure V, or Cure VI.
+ classes.SpellMaps = spell_maps
+ -- List of spells and spell maps that don't benefit from greater skill (though
+ -- they may benefit from spell-specific augments, such as improved regen or refresh).
+ -- Spells that fall under this category will be skipped when searching for
+ -- spell.skill sets.
+ classes.NoSkillSpells = no_skill_spells_list
+ classes.SkipSkillCheck = false
+ -- Custom, job-defined class, like the generic spell mappings.
+ -- Takes precedence over default spell maps.
+ -- Is reset at the end of each spell casting cycle (ie: at the end of aftercast).
+ classes.CustomClass = nil
+ classes.JAMode = nil
+ -- Custom groups used for defining melee and idle sets. Persists long-term.
+ classes.CustomMeleeGroups = L{}
+ classes.CustomRangedGroups = L{}
+ classes.CustomIdleGroups = L{}
+ classes.CustomDefenseGroups = L{}
+
+ -- Class variables for time-based flags
+ classes.Daytime = false
+ classes.DuskToDawn = false
+
+
+ -- Special control flags.
+ mote_vars = {}
+ mote_vars.show_set = nil
+ mote_vars.set_breadcrumbs = L{}
+
+ -- Display text mapping.
+ on_off_names = {[true] = 'on', [false] = 'off'}
+ on_off_values = T{'on', 'off', 'true', 'false'}
+ true_values = T{'on', 'true'}
+
+
+ -- Subtables within the sets table that we expect to exist, and are annoying to have to
+ -- define within each individual job file. We can define them here to make sure we don't
+ -- have to check for existence. The job file should be including this before defining
+ -- any sets, so any changes it makes will override these anyway.
+ sets.precast = {}
+ sets.precast.FC = {}
+ sets.precast.JA = {}
+ sets.precast.WS = {}
+ sets.precast.RA = {}
+ sets.midcast = {}
+ sets.midcast.RA = {}
+ sets.midcast.Pet = {}
+ sets.idle = {}
+ sets.resting = {}
+ sets.engaged = {}
+ sets.defense = {}
+ sets.buff = {}
+
+ gear = {}
+ gear.default = {}
+
+ gear.ElementalGorget = {name=""}
+ gear.ElementalBelt = {name=""}
+ gear.ElementalObi = {name=""}
+ gear.ElementalCape = {name=""}
+ gear.ElementalRing = {name=""}
+ gear.FastcastStaff = {name=""}
+ gear.RecastStaff = {name=""}
+
+
+ -- Load externally-defined information (info that we don't want to change every time this file is updated).
+
+ -- Used to define misc utility functions that may be useful for this include or any job files.
+ include('Mote-Utility')
+
+ -- Used for all self-command handling.
+ include('Mote-SelfCommands')
+
+ -- Include general user globals, such as custom binds or gear tables.
+ -- Load Mote-Globals first, followed by User-Globals, followed by <character>-Globals.
+ -- Any functions re-defined in the later includes will overwrite the earlier versions.
+ include('Mote-Globals')
+ optional_include({'user-globals.lua'})
+ optional_include({player.name..'-globals.lua'})
+
+ -- *-globals.lua may define additional sets to be added to the local ones.
+ if define_global_sets then
+ define_global_sets()
+ end
+
+ -- Global default binds (either from Mote-Globals or user-globals)
+ (binds_on_load or global_on_load)()
+
+ -- Load a sidecar file for the job (if it exists) that may re-define init_gear_sets and file_unload.
+ load_sidecar(player.main_job)
+
+ -- General var initialization and setup.
+ if job_setup then
+ job_setup()
+ end
+
+ -- User-specific var initialization and setup.
+ if user_setup then
+ user_setup()
+ end
+
+ -- Load up all the gear sets.
+ init_gear_sets()
+end
+
+-- Auto-initialize the include
+init_include()
+
+-- Called when this job file is unloaded (eg: job change)
+-- Conditional definition so that it doesn't overwrite explicit user
+-- versions of this function.
+if not file_unload then
+ file_unload = function()
+ if user_unload then
+ user_unload()
+ elseif job_file_unload then
+ job_file_unload()
+ end
+ _G[(binds_on_unload and 'binds_on_unload') or 'global_on_unload']()
+ end
+end
+
+
+-------------------------------------------------------------------------------------------------------------------
+-- Generalized functions for handling precast/midcast/aftercast for player-initiated actions.
+-- This depends on proper set naming.
+-- Global hooks can be written as user_xxx() to override functions at a global level.
+-- Each job can override any of these general functions using job_xxx() hooks.
+-------------------------------------------------------------------------------------------------------------------
+
+------------------------------------------------------------------------
+-- Generic function to map a set processing order to all action events.
+------------------------------------------------------------------------
+
+
+-- Process actions in a specific order of events:
+-- Filter - filter_xxx() functions determine whether to run any of the code for this action.
+-- Global - user_xxx() functions get called first. Define in Mote-Globals or User-Globals.
+-- Local - job_xxx() functions get called next. Define in JOB.lua file.
+-- Default - default_xxx() functions get called next. Defined in this file.
+-- Cleanup - cleanup_xxx() functions always get called before exiting.
+--
+-- Parameters:
+-- spell - standard spell table passed in by GearSwap
+-- action - string defining the function mapping to use (precast, midcast, etc)
+function handle_actions(spell, action)
+ -- Init an eventArgs that allows cancelling.
+ local eventArgs = {handled = false, cancel = false}
+
+ mote_vars.set_breadcrumbs:clear()
+
+ -- Get the spell mapping, since we'll be passing it to various functions and checks.
+ local spellMap = get_spell_map(spell)
+
+ -- General filter checks to see whether this function should be run.
+ -- If eventArgs.cancel is set, cancels this function, not the spell.
+ if _G['filter_'..action] then
+ _G['filter_'..action](spell, spellMap, eventArgs)
+ end
+
+ -- If filter didn't cancel it, process user and default actions.
+ if not eventArgs.cancel then
+ -- Global user handling of this action
+ if _G['user_'..action] then
+ _G['user_'..action](spell, action, spellMap, eventArgs)
+
+ if eventArgs.cancel then
+ cancel_spell()
+ end
+ end
+
+ -- Job-specific handling of this action
+ if not eventArgs.cancel and not eventArgs.handled and _G['job_'..action] then
+ _G['job_'..action](spell, action, spellMap, eventArgs)
+
+ if eventArgs.cancel then
+ cancel_spell()
+ end
+ end
+
+ -- Default handling of this action
+ if not eventArgs.cancel and not eventArgs.handled and _G['default_'..action] then
+ _G['default_'..action](spell, spellMap)
+ display_breadcrumbs(spell, spellMap, action)
+ end
+
+ -- Job-specific post-handling of this action
+ if not eventArgs.cancel and _G['job_post_'..action] then
+ _G['job_post_'..action](spell, action, spellMap, eventArgs)
+ end
+ end
+
+ -- Cleanup once this action is done
+ if _G['cleanup_'..action] then
+ _G['cleanup_'..action](spell, spellMap, eventArgs)
+ end
+end
+
+
+--------------------------------------
+-- Action hooks called by GearSwap.
+--------------------------------------
+
+function pretarget(spell)
+ handle_actions(spell, 'pretarget')
+end
+
+function precast(spell)
+ if state.Buff[spell.english] ~= nil then
+ state.Buff[spell.english] = true
+ end
+ handle_actions(spell, 'precast')
+end
+
+function midcast(spell)
+ handle_actions(spell, 'midcast')
+end
+
+function aftercast(spell)
+ if state.Buff[spell.english] ~= nil then
+ state.Buff[spell.english] = not spell.interrupted or buffactive[spell.english] or false
+ end
+ handle_actions(spell, 'aftercast')
+end
+
+function pet_midcast(spell)
+ handle_actions(spell, 'pet_midcast')
+end
+
+function pet_aftercast(spell)
+ handle_actions(spell, 'pet_aftercast')
+end
+
+--------------------------------------
+-- Default code for each action.
+--------------------------------------
+
+function default_pretarget(spell, spellMap)
+ auto_change_target(spell, spellMap)
+end
+
+function default_precast(spell, spellMap)
+ equip(get_precast_set(spell, spellMap))
+end
+
+function default_midcast(spell, spellMap)
+ equip(get_midcast_set(spell, spellMap))
+end
+
+function default_aftercast(spell, spellMap)
+ if not pet_midaction() then
+ handle_equipping_gear(player.status)
+ end
+end
+
+function default_pet_midcast(spell, spellMap)
+ equip(get_pet_midcast_set(spell, spellMap))
+end
+
+function default_pet_aftercast(spell, spellMap)
+ handle_equipping_gear(player.status)
+end
+
+--------------------------------------
+-- Filters for each action.
+-- Set eventArgs.cancel to true to stop further processing.
+-- May show notification messages, but should not do any processing here.
+--------------------------------------
+
+function filter_midcast(spell, spellMap, eventArgs)
+ if mote_vars.show_set == 'precast' then
+ eventArgs.cancel = true
+ end
+end
+
+function filter_aftercast(spell, spellMap, eventArgs)
+ if mote_vars.show_set == 'precast' or mote_vars.show_set == 'midcast' or mote_vars.show_set == 'pet_midcast' then
+ eventArgs.cancel = true
+ elseif spell.name == 'Unknown Interrupt' then
+ eventArgs.cancel = true
+ end
+end
+
+function filter_pet_midcast(spell, spellMap, eventArgs)
+ -- If we have show_set active for precast or midcast, don't try to equip pet midcast gear.
+ if mote_vars.show_set == 'precast' or mote_vars.show_set == 'midcast' then
+ add_to_chat(104, 'Show Sets: Pet midcast not equipped.')
+ eventArgs.cancel = true
+ end
+end
+
+function filter_pet_aftercast(spell, spellMap, eventArgs)
+ -- If show_set is flagged for precast or midcast, don't try to equip aftercast gear.
+ if mote_vars.show_set == 'precast' or mote_vars.show_set == 'midcast' or mote_vars.show_set == 'pet_midcast' then
+ eventArgs.cancel = true
+ end
+end
+
+--------------------------------------
+-- Cleanup code for each action.
+--------------------------------------
+
+function cleanup_precast(spell, spellMap, eventArgs)
+ -- If show_set is flagged for precast, notify that we won't try to equip later gear.
+ if mote_vars.show_set == 'precast' then
+ add_to_chat(104, 'Show Sets: Stopping at precast.')
+ end
+end
+
+function cleanup_midcast(spell, spellMap, eventArgs)
+ -- If show_set is flagged for midcast, notify that we won't try to equip later gear.
+ if mote_vars.show_set == 'midcast' then
+ add_to_chat(104, 'Show Sets: Stopping at midcast.')
+ end
+end
+
+function cleanup_aftercast(spell, spellMap, eventArgs)
+ -- Reset custom classes after all possible precast/midcast/aftercast/job-specific usage of the value.
+ -- If we're in the middle of a pet action, pet_aftercast will handle clearing it.
+ if not pet_midaction() then
+ reset_transitory_classes()
+ end
+end
+
+function cleanup_pet_midcast(spell, spellMap, eventArgs)
+ -- If show_set is flagged for pet midcast, notify that we won't try to equip later gear.
+ if mote_vars.show_set == 'pet_midcast' then
+ add_to_chat(104, 'Show Sets: Stopping at pet midcast.')
+ end
+end
+
+function cleanup_pet_aftercast(spell, spellMap, eventArgs)
+ -- Reset custom classes after all possible precast/midcast/aftercast/job-specific usage of the value.
+ reset_transitory_classes()
+end
+
+
+-- Clears the values from classes that only exist til the action is complete.
+function reset_transitory_classes()
+ classes.CustomClass = nil
+ classes.JAMode = nil
+end
+
+
+
+-------------------------------------------------------------------------------------------------------------------
+-- High-level functions for selecting and equipping gear sets.
+-------------------------------------------------------------------------------------------------------------------
+
+-- Central point to call to equip gear based on status.
+-- Status - Player status that we're using to define what gear to equip.
+function handle_equipping_gear(playerStatus, petStatus)
+ -- init a new eventArgs
+ local eventArgs = {handled = false}
+
+ -- Allow jobs to override this code
+ if job_handle_equipping_gear then
+ job_handle_equipping_gear(playerStatus, eventArgs)
+ end
+
+ -- Equip default gear if job didn't handle it.
+ if not eventArgs.handled then
+ equip_gear_by_status(playerStatus, petStatus)
+ end
+end
+
+
+-- Function to wrap logic for equipping gear on aftercast, status change, or user update.
+-- @param status : The current or new player status that determines what sort of gear to equip.
+function equip_gear_by_status(playerStatus, petStatus)
+ if _global.debug_mode then add_to_chat(123,'Debug: Equip gear for status ['..tostring(status)..'], HP='..tostring(player.hp)) end
+
+ playerStatus = playerStatus or player.status or 'Idle'
+
+ -- If status not defined, treat as idle.
+ -- Be sure to check for positive HP to make sure they're not dead.
+ if (playerStatus == 'Idle' or playerStatus == '') and player.hp > 0 then
+ equip(get_idle_set(petStatus))
+ elseif playerStatus == 'Engaged' then
+ equip(get_melee_set(petStatus))
+ elseif playerStatus == 'Resting' then
+ equip(get_resting_set(petStatus))
+ end
+end
+
+
+-------------------------------------------------------------------------------------------------------------------
+-- Functions for constructing default gear sets based on status.
+-------------------------------------------------------------------------------------------------------------------
+
+-- Returns the appropriate idle set based on current state values and location.
+-- Set construction order (all of which are optional):
+-- sets.idle[idleScope][state.IdleMode][Pet[Engaged]][CustomIdleGroups]
+--
+-- Params:
+-- petStatus - Optional explicit definition of pet status.
+function get_idle_set(petStatus)
+ local idleSet = sets.idle
+
+ if not idleSet then
+ return {}
+ end
+
+ mote_vars.set_breadcrumbs:append('sets')
+ mote_vars.set_breadcrumbs:append('idle')
+
+ local idleScope
+
+ if buffactive.weakness then
+ idleScope = 'Weak'
+ elseif areas.Cities:contains(world.area) then
+ idleScope = 'Town'
+ else
+ idleScope = 'Field'
+ end
+
+ if idleSet[idleScope] then
+ idleSet = idleSet[idleScope]
+ mote_vars.set_breadcrumbs:append(idleScope)
+ end
+
+ if idleSet[state.IdleMode] then
+ idleSet = idleSet[state.IdleMode]
+ mote_vars.set_breadcrumbs:append(state.IdleMode)
+ end
+
+ if (pet.isvalid or state.Buff.Pet) and idleSet.Pet then
+ idleSet = idleSet.Pet
+ petStatus = petStatus or pet.status
+ mote_vars.set_breadcrumbs:append('Pet')
+
+ if petStatus == 'Engaged' and idleSet.Engaged then
+ idleSet = idleSet.Engaged
+ mote_vars.set_breadcrumbs:append('Engaged')
+ end
+ end
+
+ for _,group in ipairs(classes.CustomIdleGroups) do
+ if idleSet[group] then
+ idleSet = idleSet[group]
+ mote_vars.set_breadcrumbs:append(group)
+ end
+ end
+
+ idleSet = apply_defense(idleSet)
+ idleSet = apply_kiting(idleSet)
+
+ if user_customize_idle_set then
+ idleSet = user_customize_idle_set(idleSet)
+ end
+
+ if customize_idle_set then
+ idleSet = customize_idle_set(idleSet)
+ end
+
+ return idleSet
+end
+
+
+-- Returns the appropriate melee set based on current state values.
+-- Set construction order (all sets after sets.engaged are optional):
+-- sets.engaged[state.CombatForm][state.CombatWeapon][state.OffenseMode][state.DefenseMode][classes.CustomMeleeGroups (any number)]
+function get_melee_set()
+ local meleeSet = sets.engaged
+
+ if not meleeSet then
+ return {}
+ end
+
+ mote_vars.set_breadcrumbs:append('sets')
+ mote_vars.set_breadcrumbs:append('engaged')
+
+ if state.CombatForm and meleeSet[state.CombatForm] then
+ meleeSet = meleeSet[state.CombatForm]
+ mote_vars.set_breadcrumbs:append(state.CombatForm)
+ end
+
+ if state.CombatWeapon and meleeSet[state.CombatWeapon] then
+ meleeSet = meleeSet[state.CombatWeapon]
+ mote_vars.set_breadcrumbs:append(state.CombatWeapon)
+ end
+
+ if meleeSet[state.OffenseMode] then
+ meleeSet = meleeSet[state.OffenseMode]
+ mote_vars.set_breadcrumbs:append(state.OffenseMode)
+ end
+
+ if meleeSet[state.DefenseMode] then
+ meleeSet = meleeSet[state.DefenseMode]
+ mote_vars.set_breadcrumbs:append(state.DefenseMode)
+ end
+
+ for _,group in ipairs(classes.CustomMeleeGroups) do
+ if meleeSet[group] then
+ meleeSet = meleeSet[group]
+ mote_vars.set_breadcrumbs:append(group)
+ end
+ end
+
+ meleeSet = apply_defense(meleeSet)
+ meleeSet = apply_kiting(meleeSet)
+
+ if customize_melee_set then
+ meleeSet = customize_melee_set(meleeSet)
+ end
+
+ if user_customize_melee_set then
+ meleeSet = user_customize_melee_set(meleeSet)
+ end
+
+ return meleeSet
+end
+
+
+-- Returns the appropriate resting set based on current state values.
+-- Set construction order:
+-- sets.resting[state.RestingMode]
+function get_resting_set()
+ local restingSet = sets.resting
+
+ if not restingSet then
+ return {}
+ end
+
+ mote_vars.set_breadcrumbs:append('sets')
+ mote_vars.set_breadcrumbs:append('resting')
+
+ if restingSet[state.RestingMode] then
+ restingSet = restingSet[state.RestingMode]
+ mote_vars.set_breadcrumbs:append(state.RestingMode)
+ end
+
+ return restingSet
+end
+
+
+-------------------------------------------------------------------------------------------------------------------
+-- Functions for constructing default gear sets based on action.
+-------------------------------------------------------------------------------------------------------------------
+
+-- Get the default precast gear set.
+function get_precast_set(spell, spellMap)
+ -- If there are no precast sets defined, bail out.
+ if not sets.precast then
+ return {}
+ end
+
+ local equipSet = sets.precast
+
+ mote_vars.set_breadcrumbs:append('sets')
+ mote_vars.set_breadcrumbs:append('precast')
+
+ -- Determine base sub-table from type of action being performed.
+
+ local cat
+
+ if spell.action_type == 'Magic' then
+ cat = 'FC'
+ elseif spell.action_type == 'Ranged Attack' then
+ cat = (sets.precast.RangedAttack and 'RangedAttack') or 'RA'
+ elseif spell.action_type == 'Ability' then
+ if spell.type == 'WeaponSkill' then
+ cat = 'WS'
+ elseif spell.type == 'JobAbility' then
+ cat = 'JA'
+ else
+ -- Allow fallback to .JA table if spell.type isn't found, for all non-weaponskill abilities.
+ cat = (sets.precast[spell.type] and spell.type) or 'JA'
+ end
+ elseif spell.action_type == 'Item' then
+ cat = 'Item'
+ end
+
+ -- If no proper sub-category is defined in the job file, bail out.
+ if cat then
+ if equipSet[cat] then
+ equipSet = equipSet[cat]
+ mote_vars.set_breadcrumbs:append(cat)
+ else
+ mote_vars.set_breadcrumbs:clear()
+ return {}
+ end
+ end
+
+ classes.SkipSkillCheck = false
+ -- Handle automatic selection of set based on spell class/name/map/skill/type.
+ equipSet = select_specific_set(equipSet, spell, spellMap)
+
+
+ -- Once we have a named base set, do checks for specialized modes (casting mode, weaponskill mode, etc).
+
+ if spell.action_type == 'Magic' then
+ if equipSet[state.CastingMode] then
+ equipSet = equipSet[state.CastingMode]
+ mote_vars.set_breadcrumbs:append(state.CastingMode)
+ end
+ elseif spell.type == 'WeaponSkill' then
+ equipSet = get_weaponskill_set(equipSet, spell, spellMap)
+ elseif spell.action_type == 'Ability' then
+ if classes.JAMode and equipSet[classes.JAMode] then
+ equipSet = equipSet[classes.JAMode]
+ mote_vars.set_breadcrumbs:append(classes.JAMode)
+ end
+ elseif spell.action_type == 'Ranged Attack' then
+ equipSet = get_ranged_set(equipSet, spell, spellMap)
+ end
+
+ -- Update defintions for element-specific gear that may be used.
+ set_elemental_gear(spell)
+
+ -- Return whatever we've constructed.
+ return equipSet
+end
+
+
+
+-- Get the default midcast gear set.
+-- This builds on sets.midcast.
+function get_midcast_set(spell, spellMap)
+ -- If there are no midcast sets defined, bail out.
+ if not sets.midcast then
+ return {}
+ end
+
+ local equipSet = sets.midcast
+
+ mote_vars.set_breadcrumbs:append('sets')
+ mote_vars.set_breadcrumbs:append('midcast')
+
+ -- Determine base sub-table from type of action being performed.
+ -- Only ranged attacks and items get specific sub-categories here.
+
+ local cat
+
+ if spell.action_type == 'Ranged Attack' then
+ cat = (sets.precast.RangedAttack and 'RangedAttack') or 'RA'
+ elseif spell.action_type == 'Item' then
+ cat = 'Item'
+ end
+
+ -- If no proper sub-category is defined in the job file, bail out.
+ if cat then
+ if equipSet[cat] then
+ equipSet = equipSet[cat]
+ mote_vars.set_breadcrumbs:append(cat)
+ else
+ mote_vars.set_breadcrumbs:clear()
+ return {}
+ end
+ end
+
+ classes.SkipSkillCheck = classes.NoSkillSpells:contains(spell.english)
+ -- Handle automatic selection of set based on spell class/name/map/skill/type.
+ equipSet = select_specific_set(equipSet, spell, spellMap)
+
+ -- After the default checks, do checks for specialized modes (casting mode, etc).
+
+ if spell.action_type == 'Magic' then
+ if equipSet[state.CastingMode] then
+ equipSet = equipSet[state.CastingMode]
+ mote_vars.set_breadcrumbs:append(state.CastingMode)
+ end
+ elseif spell.action_type == 'Ranged Attack' then
+ equipSet = get_ranged_set(equipSet, spell, spellMap)
+ end
+
+ -- Return whatever we've constructed.
+ return equipSet
+end
+
+
+-- Get the default pet midcast gear set.
+-- This is built in sets.midcast.Pet.
+function get_pet_midcast_set(spell, spellMap)
+ -- If there are no midcast sets defined, bail out.
+ if not sets.midcast or not sets.midcast.Pet then
+ return {}
+ end
+
+ local equipSet = sets.midcast.Pet
+
+ mote_vars.set_breadcrumbs:append('sets')
+ mote_vars.set_breadcrumbs:append('midcast')
+ mote_vars.set_breadcrumbs:append('Pet')
+
+ if sets.midcast and sets.midcast.Pet then
+ classes.SkipSkillCheck = false
+ equipSet = select_specific_set(equipSet, spell, spellMap)
+
+ -- We can only generally be certain about whether the pet's action is
+ -- Magic (ie: it cast a spell of its own volition) or Ability (it performed
+ -- an action at the request of the player). Allow CastinMode and
+ -- OffenseMode to refine whatever set was selected above.
+ if spell.action_type == 'Magic' then
+ if equipSet[state.CastingMode] then
+ equipSet = equipSet[state.CastingMode]
+ mote_vars.set_breadcrumbs:append(state.CastingMode)
+ end
+ elseif spell.action_type == 'Ability' then
+ if equipSet[state.OffenseMode] then
+ equipSet = equipSet[state.OffenseMode]
+ mote_vars.set_breadcrumbs:append(state.OffenseMode)
+ end
+ end
+ end
+
+ return equipSet
+end
+
+
+-- Function to handle the logic of selecting the proper weaponskill set.
+function get_weaponskill_set(equipSet, spell, spellMap)
+ -- Custom handling for weaponskills
+ local ws_mode = state.WeaponskillMode
+
+ if ws_mode == 'Normal' then
+ -- If a particular weaponskill mode isn't specified, see if we have a weaponskill mode
+ -- corresponding to the current offense mode. If so, use that.
+ if spell.skill == 'Archery' or spell.skill == 'Marksmanship' then
+ if state.RangedMode ~= 'Normal' and S(options.WeaponskillModes):contains(state.RangedMode) then
+ ws_mode = state.RangedMode
+ end
+ else
+ if state.OffenseMode ~= 'Normal' and S(options.WeaponskillModes):contains(state.OffenseMode) then
+ ws_mode = state.OffenseMode
+ end
+ end
+ end
+
+ local custom_wsmode
+
+ -- Allow the job file to specify a preferred weaponskill mode
+ if get_custom_wsmode then
+ custom_wsmode = get_custom_wsmode(spell, spellMap, ws_mode)
+ end
+
+ -- If the job file returned a weaponskill mode, use that.
+ if custom_wsmode then
+ ws_mode = custom_wsmode
+ end
+
+ if equipSet[ws_mode] then
+ equipSet = equipSet[ws_mode]
+ mote_vars.set_breadcrumbs:append(ws_mode)
+ end
+
+ return equipSet
+end
+
+
+-- Function to handle the logic of selecting the proper ranged set.
+function get_ranged_set(equipSet, spell, spellMap)
+ -- Attach Combat Form and Combat Weapon to set checks
+ if state.CombatForm and equipSet[state.CombatForm] then
+ equipSet = equipSet[state.CombatForm]
+ mote_vars.set_breadcrumbs:append(state.CombatForm)
+ end
+
+ if state.CombatWeapon and equipSet[state.CombatWeapon] then
+ equipSet = equipSet[state.CombatWeapon]
+ mote_vars.set_breadcrumbs:append(state.CombatWeapon)
+ end
+
+ -- Check for specific mode for ranged attacks (eg: Acc, Att, etc)
+ if equipSet[state.RangedMode] then
+ equipSet = equipSet[state.RangedMode]
+ mote_vars.set_breadcrumbs:append(state.RangedMode)
+ end
+
+ -- Tack on any additionally specified custom groups, if the sets are defined.
+ for _,group in ipairs(classes.CustomRangedGroups) do
+ if equipSet[group] then
+ equipSet = equipSet[group]
+ mote_vars.set_breadcrumbs:append(group)
+ end
+ end
+
+ return equipSet
+end
+
+
+-------------------------------------------------------------------------------------------------------------------
+-- Functions for optional supplemental gear overriding the default sets defined above.
+-------------------------------------------------------------------------------------------------------------------
+
+-- Function to apply any active defense set on top of the supplied set
+-- @param baseSet : The set that any currently active defense set will be applied on top of. (gear set table)
+function apply_defense(baseSet)
+ if state.Defense.Active then
+ local defenseSet = sets.defense
+
+ if state.Defense.Type == 'Physical' then
+ defenseSet = sets.defense[state.Defense.PhysicalMode] or defenseSet
+ else
+ defenseSet = sets.defense[state.Defense.MagicalMode] or defenseSet
+ end
+
+ for _,group in ipairs(classes.CustomDefenseGroups) do
+ defenseSet = defenseSet[group] or defenseSet
+ end
+
+ baseSet = set_combine(baseSet, defenseSet)
+ end
+
+ return baseSet
+end
+
+
+-- Function to add kiting gear on top of the base set if kiting state is true.
+-- @param baseSet : The gear set that the kiting gear will be applied on top of.
+function apply_kiting(baseSet)
+ if state.Kiting then
+ if sets.Kiting then
+ baseSet = set_combine(baseSet, sets.Kiting)
+ end
+ end
+
+ return baseSet
+end
+
+
+-------------------------------------------------------------------------------------------------------------------
+-- Utility functions for constructing default gear sets.
+-------------------------------------------------------------------------------------------------------------------
+
+-- Get a spell mapping for the spell.
+function get_spell_map(spell)
+ local defaultSpellMap = classes.SpellMaps[spell.english]
+ local jobSpellMap
+
+ if job_get_spell_map then
+ jobSpellMap = job_get_spell_map(spell, defaultSpellMap)
+ end
+
+ return jobSpellMap or defaultSpellMap
+end
+
+
+-- Select the equipment set to equip from a given starting table, based on standard
+-- selection order: custom class, spell name, spell map, spell skill, and spell type.
+-- Spell skill and spell type may further refine their selections based on
+-- custom class, spell name and spell map.
+function select_specific_set(equipSet, spell, spellMap)
+ -- Take the determined base equipment set and try to get the simple naming extensions that
+ -- may apply to it (class, spell name, spell map).
+ local namedSet = get_named_set(equipSet, spell, spellMap)
+
+ -- If no simple naming sub-tables were found, and we simply got back the original equip set,
+ -- check for spell.skill and spell.type, then check the simple naming extensions again.
+ if namedSet == equipSet then
+ if spell.skill and equipSet[spell.skill] and not classes.SkipSkillCheck then
+ namedSet = equipSet[spell.skill]
+ mote_vars.set_breadcrumbs:append(spell.skill)
+ elseif spell.type and equipSet[spell.type] then
+ namedSet = equipSet[spell.type]
+ mote_vars.set_breadcrumbs:append(spell.type)
+ else
+ return equipSet
+ end
+
+ namedSet = get_named_set(namedSet, spell, spellMap)
+ end
+
+ return namedSet or equipSet
+end
+
+
+-- Simple utility function to handle a portion of the equipment set determination.
+-- It attempts to select a sub-table of the provided equipment set based on the
+-- standard search order of custom class, spell name, and spell map.
+-- If no such set is found, it returns the original base set (equipSet) provided.
+function get_named_set(equipSet, spell, spellMap)
+ if equipSet then
+ if classes.CustomClass and equipSet[classes.CustomClass] then
+ mote_vars.set_breadcrumbs:append(classes.CustomClass)
+ return equipSet[classes.CustomClass]
+ elseif equipSet[spell.english] then
+ mote_vars.set_breadcrumbs:append(spell.english)
+ return equipSet[spell.english]
+ elseif spellMap and equipSet[spellMap] then
+ mote_vars.set_breadcrumbs:append(spellMap)
+ return equipSet[spellMap]
+ else
+ return equipSet
+ end
+ end
+end
+
+
+-------------------------------------------------------------------------------------------------------------------
+-- Hooks for other events.
+-------------------------------------------------------------------------------------------------------------------
+
+-- Called when the player's subjob changes.
+function sub_job_change(newSubjob, oldSubjob)
+ if user_setup then
+ user_setup()
+ end
+
+ if job_sub_job_change then
+ job_sub_job_change(newSubjob, oldSubjob)
+ end
+
+ send_command('gs c update')
+end
+
+
+-- Called when the player's status changes.
+function status_change(newStatus, oldStatus)
+ -- init a new eventArgs
+ local eventArgs = {handled = false}
+ mote_vars.set_breadcrumbs:clear()
+
+ -- Allow a global function to be called on status change.
+ if user_status_change then
+ user_status_change(newStatus, oldStatus, eventArgs)
+ end
+
+ -- Then call individual jobs to handle status change events.
+ if not eventArgs.handled then
+ if job_status_change then
+ job_status_change(newStatus, oldStatus, eventArgs)
+ end
+ end
+
+ -- Handle equipping default gear if the job didn't mark this as handled.
+ if not eventArgs.handled then
+ handle_equipping_gear(newStatus)
+ display_breadcrumbs()
+ end
+end
+
+
+-- Called when a player gains or loses a buff.
+-- buff == buff gained or lost
+-- gain == true if the buff was gained, false if it was lost.
+function buff_change(buff, gain)
+ -- Init a new eventArgs
+ local eventArgs = {handled = false}
+
+ if state.Buff[buff] ~= nil then
+ state.Buff[buff] = gain
+ end
+
+ -- Allow a global function to be called on buff change.
+ if user_buff_change then
+ user_buff_change(buff, gain, eventArgs)
+ end
+
+ -- Allow jobs to handle buff change events.
+ if not eventArgs.handled then
+ if job_buff_change then
+ job_buff_change(buff, gain, eventArgs)
+ end
+ end
+end
+
+
+-- Called when a player gains or loses a pet.
+-- pet == pet gained or lost
+-- gain == true if the pet was gained, false if it was lost.
+function pet_change(pet, gain)
+ -- Init a new eventArgs
+ local eventArgs = {handled = false}
+
+ -- Allow jobs to handle pet change events.
+ if job_pet_change then
+ job_pet_change(pet, gain, eventArgs)
+ end
+
+ -- Equip default gear if not handled by the job.
+ if not eventArgs.handled then
+ handle_equipping_gear(player.status)
+ end
+end
+
+
+-- Called when the player's pet's status changes.
+-- Note that this is also called after pet_change when the pet is released.
+-- As such, don't automatically handle gear equips. Only do so if directed
+-- to do so by the job.
+function pet_status_change(newStatus, oldStatus)
+ -- Init a new eventArgs
+ local eventArgs = {handled = false}
+
+ -- Allow jobs to override this code
+ if job_pet_status_change then
+ job_pet_status_change(newStatus, oldStatus, eventArgs)
+ end
+end
+
+
+-------------------------------------------------------------------------------------------------------------------
+-- Debugging functions.
+-------------------------------------------------------------------------------------------------------------------
+
+-- This is a debugging function that will print the accumulated set selection
+-- breadcrumbs for the default selected set for any given action stage.
+function display_breadcrumbs(spell, spellMap, action)
+ if not _settings.debug_mode then
+ return
+ end
+
+ local msg = 'Default '
+
+ if action and spell then
+ msg = msg .. action .. ' set selection for ' .. spell.name
+ end
+
+ if spellMap then
+ msg = msg .. ' (' .. spellMap .. ')'
+ end
+ msg = msg .. ' : '
+
+ local cons
+
+ for _,name in ipairs(mote_vars.set_breadcrumbs) do
+ if not cons then
+ cons = name
+ else
+ if name:contains(' ') or name:contains("'") then
+ cons = cons .. '["' .. name .. '"]'
+ else
+ cons = cons .. '.' .. name
+ end
+ end
+ end
+
+ if cons then
+ if action and cons == ('sets.' .. action) then
+ msg = msg .. "None"
+ else
+ msg = msg .. tostring(cons)
+ end
+ add_to_chat(123, msg)
+ end
+end
+
+