Skip to content

Community Lua Functions

Ahernika edited this page Jul 31, 2024 · 43 revisions

Hey! If you're reading this you're probably looking for a place that a lot of commonly used functions that we all steal borrow of each other. (All in good fun). Note you don't HAVE to use these, and if you have some way to improve them, please feel free to add to it!

Functions

MoveTo

This function makes the player fly or walk to a specified location, ensuring the navmesh is ready before proceeding. takes an X, Y, Z, Stop Distance, and Boolean (True/False)

-- needs vnavmesh
function MoveTo(valuex, valuey, valuez, stopdistance, FlyOrWalk)
  function MeshCheck()
      function Truncate1Dp(num)
          return truncate and ("%.1f"):format(num) or num
      end
      local was_ready = NavIsReady()
      if not NavIsReady() then
          while not NavIsReady() do
              LogInfo("[Debug]Building navmesh, currently at " .. Truncate1Dp(NavBuildProgress() * 100) .. "%")
              yield("/wait 1")
              local was_ready = NavIsReady()
              if was_ready then
                  LogInfo("[Debug]Navmesh ready!")
              end
          end
      else
          LogInfo("[Debug]Navmesh ready!")
      end
  end
  MeshCheck()
  if FlyOrWalk then
      if TerritorySupportsMounting() then
          while GetCharacterCondition(4, false) do
              yield("/wait 0.1")
              if GetCharacterCondition(27) then
                  yield("/wait 2")
              else
                  yield('/gaction "mount roulette"')
              end
          end
          if HasFlightUnlocked(GetZoneID()) then
              PathfindAndMoveTo(valuex, valuey, valuez, true) -- flying
          else
              LogInfo("[MoveTo] Can't fly trying to walk.")
              PathfindAndMoveTo(valuex, valuey, valuez, false) -- walking
          end
      else
          LogInfo("[MoveTo] Can't mount trying to walk.")
          PathfindAndMoveTo(valuex, valuey, valuez, false) -- walking
      end
  else
      PathfindAndMoveTo(valuex, valuey, valuez, false) -- walking
  end
  while ((PathIsRunning() or PathfindInProgress()) and GetDistanceToPoint(valuex, valuey, valuez) > stopdistance) do
      yield("/wait 0.3")
  end
  PathStop()
  LogInfo("[MoveTo] Completed")
end

Example usage:

MoveTo(-242.07663, -43.815063, 665.1687, 1, true) --Flies to Coordinates
MoveTo(-162.892, 0.922, -30.488, 3, false) --Walks to coordinates
setSNDProperty

Use these Functions to Set or Unset SND Properties.

--[[
All the settings you can edit with SetSNDProperty()

CraftLoopFromRecipeNote -- bool
CraftLoopMaxWait -- int
CraftLoopEcho -- bool
MaxTimeoutRetries -- int
NoisyErrors -- bool
BeepFrequency -- int
BeepDuration -- int
BeepCount -- int
UseSNDTargeting -- bool
UseItemStructsVersion -- bool
StopMacroIfActionTimeout -- bool
StopMacroIfItemNotFound -- bool
StopMacroIfCantUseItem -- bool
StopMacroIfTargetNotFound -- bool
StopMacroIfAddonNotFound -- bool
StopMacroIfAddonNotVisible -- bool

--]]

-- Function to set or unset the property
function setSNDProperty(propertyName, value)
  local currentValue = GetSNDProperty(propertyName)
  if currentValue ~= value then
      SetSNDProperty(propertyName, tostring(value))
      LogInfo("[SetSNDProperty] " .. propertyName .. " set to " .. tostring(value))
  end
end

Example usage:

setSNDProperty("UseItemStructsVersion", true)
setSNDProperty("UseSNDTargeting", true)
setSNDProperty("StopMacroIfTargetNotFound", false)
setSNDProperty("StopMacroIfCantUseItem", false)
setSNDProperty("StopMacroIfItemNotFound", false)
setSNDProperty("StopMacroIfAddonNotFound", false)
PlayerTest

Waits Until Player is Ready.

  -- This function will wait until player is ready can be used in map changes, menu exit waits ex.
  function PlayerTest()
      repeat
          yield("/wait 0.5")
      until IsPlayerAvailable()
  end

Example usage:

PlayerTest()
EatFood

Eats Food if you don't have any.

function EatFood(FoodKind, StopIfNoFood)
  -- Check if the food effect is not active and if using food is enabled
  if not HasStatusId(48) and UseFood then
      while not HasStatusId(48) and UseFood do
          yield("/item " .. FoodKind)
          yield("/wait 2")
          
          -- Check if there was an error indicating no food remaining
          if GetNodeText("_TextError", 1) == "You do not have that item." and IsAddonVisible("_TextError") then
              UseFood = false
              LogInfo("[FoodCheck] No food remaining, setting UseFood to false")
              
              -- Stop the script if the flag is set
              if StopIfNoFood then
                  LogInfo("[FoodCheck] StopIfNoFood is true, stopping the script")
                  yield("/snd stop")
              end
              
              break
          end
      end
      LogInfo("[FoodCheck] Completed")
  else
      LogInfo("[FoodCheck] Already has food status or UseFood is false")
  end
end

Example usage:

EatFood("Vegetable Soup <HQ>", false) --make sure to have the name of the food IN the "" and <HQ> for HQ food,  if set to True will stop script when food runs out.
RandomSpot

Returns a Random X Y Z coordinate from a Variable List. Variable Lists should include 4 pieces of information in them. X value, Y value, Z value, Spot value. The Spot value allows you to use the same List Variable for multiple slots. Included in the code below are three coordinates sets for 3 different spots. When Calling the Function it looks for the value for the spot to pick from.

FishingSpot =
{
{520.7,193.7,-518.1,0}, -- First spot
{521.4,193.3,-522.2,0},
{526.3,192.6,-527.2,0},

{544.6,192.4,-507.8, 1}, -- Second spot
{536.9,192.2,-503.2, 1},
{570.3,189.4,-502.7, 1},

{422.9,-191.2,-300.2, 500} --bailout
}

function RandomSpot(Value)
  local availableSpots = {} -- Table to store available spot indices

  for i, spot in ipairs(FishingSpot) do
      if spot[4] == Value then
          table.insert(availableSpots, i)
      end
  end
  if #availableSpots > 0 then
      local randomIndex = math.random(1, #availableSpots)
      local spotIndex = availableSpots[randomIndex]

      local spot = FishingSpot[spotIndex]
      local x, y, z = spot[1], spot[2], spot[3]
      return x, y, z

  else
      LogInfo("[Debug]No available spots")
      return nil, nil, nil
  end
end

Example usage:

X, Y, Z = RandomSpot(1) -- Calls a random X, Y, Z Value from the coordinates in the above code from the (2nd spots which is marked with a 1)
NpcRepair

Selects the Named NPC to repair.

function NpcRepair(Name)
    while true do
        if not NeedsRepair(RepairAmount) then
            break
        elseif GetTargetName() ~= Name then
            yield("/target " .. Name)
            yield("/wait 0.1")
        elseif IsAddonVisible("SelectIconString") then
            yield("/callback SelectIconString true 1")
        elseif IsAddonVisible("SelectYesno") then
            yield("/callback SelectYesno true 0")
            yield("/wait 0.1")
        elseif IsAddonVisible("Repair") then
            yield("/callback Repair true 0")
        else
            yield("/interact")
        end
        yield("/wait 0.3")
    end
    while IsAddonVisible("Repair") do
        yield("/callback Repair true -1")
        yield("/wait 0.1")
    end
    LogInfo("[RepairNpc]Got Repaired by " .. Name .. " .")
end

Example usage:

NpcRepair("Mender")
SelfRepair

Self repairs gear.

function SelfRepair(RepairAmount, StopIfNoDarkMatter)
  if NeedsRepair(RepairAmount)then
      while not IsAddonVisible("Repair") do
          yield("/generalaction repair")
          yield("/wait 0.5")
      end
      yield("/callback Repair true 0")
      yield("/wait 0.1")
      if GetNodeText("_TextError", 1) == "You do not have the dark matter required to repair that item." and
          IsAddonVisible("_TextError") then
                      LogInfo("[Repair] Set to False not enough dark matter")
          if StopIfNoDarkMatter then
              yield("/snd stop")
          end
      end
      if IsAddonVisible("SelectYesno") then
          yield("/callback SelectYesno true 0")
      end
      while GetCharacterCondition(39) do
          yield("/wait 1")
      end
      yield("/wait 1")
      if IsAddonVisible("Repair") then
          yield("/callback Repair true -1")
      end
  end
  LogInfo("[Repair] Completed")
  
end

Example usage:

SelfRepair(50, false) --does a Self Repair when gear score is below 50 but does not stop the script if you have no dark matter. (set to true to stop script if you have no dark matter.)
TeleportTo

Checks if you are all ready in the area before teleporting to location. Requires the Teleporter Plugin.

function TeleportTo(town, targetZoneID)
  local currentZone = GetZoneID()
  
  if currentZone ~= targetZoneID then
      -- Teleport to the specified location
      local teleportCommand = "/tp " .. town
      yield(teleportCommand)
      yield("/wait 10")  -- Wait for the teleport to complete
      
      -- Check if the teleport was successful
      currentZone = GetZoneID()
      if currentZone == targetZoneID then
          yield("/echo Teleport successful. Now at Zone ID " .. targetZoneID .. ".")
      else
          yield("/echo Teleport failed. Still at Zone ID " .. currentZone .. ".")
      end
  end
end

Example usage:

TeleportTo("Solution Nine", 1186)
MateriaExtract

Extracts Materia from current Gear at 100% soulbond.

function MateriaExtract()
  if CanExtractMateria(100) then
      yield("/generalaction \"Materia Extraction\"")
      yield("/waitaddon Materialize")

      while CanExtractMateria(100) == true do
          yield("/callback Materialize true 2 0")
          yield("/wait 0.5")
if IsAddonVisible("MaterializeDialog") then
yield("/callback MaterializeDialog true 0")
end
          while GetCharacterCondition(39) do
              yield("/wait 3")
          end
          yield("/wait 2")
      end

      yield("/wait 1")
      yield("/callback Materialize true -1")
  end
end

Example usage

MateriaExtract()
Collectable Appraiser & Scrip Exchange

Turns in given collectible and Exchanges scrips for set items

function CollectableAppraiser()
  while not IsAddonVisible("CollectablesShop") and not IsAddonReady("CollectablesShop") do
      if GetTargetName() ~= "Collectable Appraiser" then
          yield("/target Collectable Appraiser")
      elseif not IsAddonVisible("SelectIconString1") then
          yield("/target")
      else
          yield("/callback SelectIconString1 true 0")
      end
      yield("/wait " .. interval_rate)
  end
  yield("/wait " .. interval_rate * 10)


  local orange_scrips_raw = GetNodeText("CollectablesShop", -1, 1):gsub(",", ""):match("^([%d,]+)/")
  local purple_scrips_raw = GetNodeText("CollectablesShop", -2, 1):gsub(",", ""):match("^([%d,]+)/")

  local orange_scrips = tonumber(orange_scrips_raw)
  local purple_scrips = tonumber(purple_scrips_raw)

  if (orange_scrips < scrip_overcap_limit) and (purple_scrips < scrip_overcap_limit) then
      for i, item in ipairs(collectible_item_table) do
          local collectible_to_turnin_row = item[1]
          local collectible_item_id = item[2]
          local job_for_turnin = item[3]
          local turnins_scrip_type = item[4]
          yield("Turnin in: " .. collectible_item_id)
          if GetItemCount(collectible_item_id) > 0 then
              yield("/callback CollectablesShop true 14 " .. job_for_turnin)
              yield("/wait " .. interval_rate)
              yield("/callback CollectablesShop true 12 " .. collectible_to_turnin_row)
              yield("/wait " .. interval_rate)
              scrips_owned = tonumber(GetNodeText("CollectablesShop", turnins_scrip_type, 1):gsub(",", ""):match("^([%d,]+)/"))
              while (scrips_owned <= scrip_overcap_limit) and (not IsAddonVisible("SelectYesno")) and (ItemCount(collectible_item_id) > 0) do
                  --iyield("ITEM: " .. collectible_item_id .. " Qty: " .. ItemCount(collectible_item_id))
                  yield("/callback CollectablesShop true 17 0")
                  yield("/wait " .. interval_rate * 2)
                  scrips_owned = tonumber(GetNodeText("CollectablesShop", turnins_scrip_type, 1):gsub(",", ""):match("^([%d,]+)/"))
              end --will break if either orange or purple scrip limit cap reached
              yield("/wait " .. interval_rate)
          end
          yield("/wait " .. interval_rate)
          if IsAddonVisible("Selectyesno") then
              yield("/callback Selectyesno true 2")
              break
          end
      end
  end
  yield("/wait " .. interval_rate)
  yield("/callback CollectablesShopo true -1")

  if GetTargetName() ~= "" then
      ClearTarget()
      yield("/wait " .. interval_rate)
  end
end

function ScripExchange()
  --EXCHANGE OPEN--
  while not IsAddonVisible("InclusionShop") and not IsAddonReady("InclusionShop") do
      if GetTargetName() ~= "Scrip Exchange" then
          yield("/target Scrip Exchange")
      elseif not IsAddonVisible("SelectIconString") then
          yield("/interact")
      else
          yield("/callback SelectIconString true 0")
      end
      yield("/wait " .. interval_rate)
  end

  yield("/wait " .. interval_rate*10)

  --EXCHANGE CATEGORY--
for i, reward in ipairs(exchange_item_table) do
  local scrip_exchange_category = reward[1]
  local scrip_exchange_subcategory = reward[2]
  local scrip_exchange_item_to_buy_row = reward[3]
  local collectible_scrip_price = reward[4]
  yield("Price:"..collectible_scrip_price)

  yield("/wait " .. interval_rate * 5)
  yield("/callback InclusionShop true 15 " .. scrip_exchange_category)
  yield("/wait " .. interval_rate)
  yield("/callback InclusionShop true 14 " .. scrip_exchange_subcategory)
  yield("/wait " .. interval_rate)

  --EXCHANGE PURCHASE--
  scrips_owned_str = GetNodeText("InclusionShop", 21):gsub(",", "")
  scrips_owned = tonumber(scrips_owned_str)
  if scrips_owned >= min_scrip_for_exchange then
      scrip_shop_item_row = scrip_exchange_item_to_buy_row + 21
      scrip_item_number_to_buy = scrips_owned // collectible_scrip_price
      local scrip_item_number_to_buy_final = math.min(scrip_item_number_to_buy,99)
      yield("/callback InclusionShop true 15 " .. scrip_exchange_item_to_buy_row .. " " .. scrip_item_number_to_buy_final)
      yield("/wait " .. interval_rate * 5)
      if IsAddonVisible("ShopExchangeItemDialog") then
          yield("/callback ShopExchangeItemDialog true 0")
          yield("/wait " .. interval_rate)
      end
  end
end
  --EXCHANGE CLOSE--
  yield("/wait " .. interval_rate)
  yield("/callback InclusionShop true -1")

  if GetTargetName() ~= "" then
      ClearTarget()
      yield("/wait " .. interval_rate)
  end
end



function CanTurnin()
  local flag = false
  for i, item in ipairs(collectible_item_table) do
      local collectible_item_id = item[2]
      if GetItemCount(collectible_item_id) >= min_items_before_turnins then
          flag = falsr --turnin even if one item is available for turnins
      end
  end
  return flag
end
function CollectableAppraiserScripExchange()
  if IsPlayerAvailable() and do_scrips then
      while CanTurnin() do
          CollectableAppraiser()
          yield("/wait " .. interval_rate)
          ScripExchange()
          yield("/wait " .. interval_rate)
      end
      yield("/wait " .. interval_rate)
      ScripExchange()
  end
end

Example usage

min_items_before_turnins=1
timeout_threshold = 10
interval_rate = 0.01
do_scrips = true
scrip_overcap_limit = 3900
--collectible_to_turnin_row, item_id, job_for_turnin, turnin_scrip_type
collectible_item_table =
{
    --MINER
    --orange scips --39 for orange scrips
    { 0, 43922, 8, 39 },                    --ra'kaznar ore
    { 1, 43923, 8, 39 },                    --ash soil
    { 3, 43921, 8, 39 },                    --magnesite ore
    --BOTANIST
    { 0, 43929, 9, 39 },                    --acacia log
    { 1, 43930, 9, 39 },                    --windsbalm bay lef
    { 3, 43928, 9, 39 },                    --dark mahagony

    --MINER
    --white scips --38 for white scrips
    { 4, 44233, 8, 38 },                    --white gold ore
    { 5, 43920, 8, 38 },                    --gold ore
    { 6, 43919, 8, 38 },                    --dark amber
    --BOTANIST
    { 4, 44234, 9, 38 },                    --acacia bark
    { 5, 43927, 9, 38 },                    --kukuru beans
    { 6, 43926, 9, 38 }                     --mountain flax
}
--scrip_exchange_category,scrip_exchange_subcategory,scrip_exchange_item_to_buy_row, collectible_scrip_price
exchange_item_table = {
    { 4, 7, 3, 200 },  --what to spend orange on (aethersands, 2 is sunglit, 4 is mythroot and so on) this will buy mythroot aethersand
--only 1 item to spend orange scrips on and one time to purple scrips on
    { 4, 1, 0, 20 },  --what to spend purple on (will buy high cordials)
}


min_scrip_for_exchange = 20
--scrip_exchange_category = 2
--3 is Gear, for gatherers
-- 4 is Master Recepies/Materials/Misc
-- 5 is Materia
--scrip_exchange_subcategory = 2
--1 PURPLE scrips
--2 ORANGE scrips
--scrip_exchange_item_to_buy_row = 0
no from the top, starting with 0, so for crafters
--0: "Craftsman's Competence Materia XII"
--1: "Craftsman's Cunning Materia XII"
--2: "Craftsman's Command Materia XII"

CollectableAppraiserScripExchange()
DoAR

Goes to Retainer bell to do retainers using Autoretainer plugin, requires VNavmesh (search for them if you don't know these plugins).

function PathToMB()

  TeleportToGCTown()
  local gc_no = GetPlayerGC()
  if gc_no == 1 then
      local zoneid = paths_to_mb[1][4]
      local x = paths_to_mb[1][1]
      local y = paths_to_mb[1][2]
      local z = paths_to_mb[1][3]
      repeat
           yield("/wait "..interval_rate)
      until (zoneid == GetZoneID()) and (not GetCharacterCondition(27)) and (not GetCharacterCondition(45)) and (not GetCharacterCondition(51))
      yield("/wait " .. interval_rate * 50)
      PathfindAndMoveTo(x, y, z, false)

  elseif gc_no == 2 then
      local zoneid = paths_to_mb[2][4]
      local x = paths_to_mb[2][1]
      local y = paths_to_mb[2][2]
      local z = paths_to_mb[2][3]
      repeat
           yield("/wait "..interval_rate)
      until (zoneid == GetZoneID()) and (not GetCharacterCondition(27)) and (not GetCharacterCondition(45)) and (not GetCharacterCondition(51))
      yield("/li leatherworker")
      yield("/wait " .. interval_rate * 50)
      PathfindAndMoveTo(x, y, z, false)

  elseif gc_no == 3 then
      local zoneid = paths_to_mb[3][4]
      local x = paths_to_mb[3][1]
      local y = paths_to_mb[3][2]
      local z = paths_to_mb[3][3]
      repeat
           yield("/wait "..interval_rate)
      until (zoneid == GetZoneID()) and (not GetCharacterCondition(27)) and (not GetCharacterCondition(45)) and (not GetCharacterCondition(51))
      yield("/li sapphire")
      yield("/wait " .. interval_rate * 50)
      PathfindAndMoveTo(x, y, z, false)

  end
  yield("/wait "..interval_rate)
  if PathIsRunning() then
     repeat
        yield("/wait "..interval_rate)
     until not PathIsRunning()
  end
end

function DoAR()
  if ARRetainersWaitingToBeProcessed(allCharacters) and do_ar then
      timeout_start = os.clock()
      if PathIsRunning() then
          repeat
             yield("/wait "..interval_rate)
          until ((not PathIsRunning()) and IsPlayerAvailable()) or (os.clock() - timeout_start > timeout_threshold)
          yield("/wait "..interval_rate)
          yield("/vnavmesh stop")
      end
      
      if not IsPlayerAvailable() then
         timeout_start = os.clock()
         repeat
            yield("/wait "..interval_rate)
         until IsPlayerAvailable() or (os.clock() - timeout_start > timeout_threshold)
      end
      
      PathToMB()
      yield("/wait "..interval_rate*3)
      yield("/target Summoning Bell")
      yield("/wait "..interval_rate*3)

      if GetTargetName() == "Summoning Bell" and GetDistanceToTarget() <= 4.5 then
          yield("/interact")
          yield("/ays multi")
          yield("/wait "..interval_rate)
          yield("/ays e")
          LogInfo("[DoAR] AR Started")
          while ARRetainersWaitingToBeProcessed(allCharacters) do
              yield("/wait "..interval_rate)
          end
      else
          yield("No Summoning Bell")
      end
      if IsAddonVisible("RetainerList") then
          yield("/callback RetainerList True -1")
          yield("/wait "..interval_rate)
      end
  
      if GetTargetName() ~= "" then
          ClearTarget()
      end
      yield("/wait "..interval_rate)
      yield("/ays multi")
  end
end

Example usage:

allCharacters = false
interval_rate = 0.1
timeout_threshold=10
do_ar=true
paths_to_mb = {
    { -124.703, 18.00, 19.887, 129 }, -- Path to Retainer Bells
    { 168.72,   15.5,  -100.06, 132 },
    { 146.760,  4,     -42.992,130 } -- This path is used in the example
}
DoAR()

Useful Code

Get Target name

Gets Target's name and returns it to chat.

yield("Target Name: "..tostring(GetTargetName()))
Current Zone ID

Gets the Current Zone ID and returns it to chat.

yield("InZone: " .. tostring(GetZoneID()))
Target Position

Gets the Current Targets X Y Z and returns it to chat.

yield("/e ------------------------------------------------------")
x = ("%.1f"):format(GetTargetRawXPos())
y = ("%.1f"):format(GetTargetRawYPos())
z = ("%.1f"):format(GetTargetRawZPos())
yield("/e Target Position: {"..x..","..y..","..z.."}")
yield("/e ------------------------------------------------------")
Players Position

Gets the Players X Y Z and returns it to chat.

yield("/e ------------------------------------------------------")
x = ("%.1f"):format(GetPlayerRawXPos())
y = ("%.1f"):format(GetPlayerRawYPos())
z = ("%.1f"):format(GetPlayerRawZPos())
yield("/e Current Position: {"..x..","..y..","..z.."}")
yield("/e ------------------------------------------------------")