├── LICENSE ├── README.md ├── Scripts ├── AutoHunt │ ├── AutoHuntLog - Helper.lua │ ├── AutoHuntLog - Main │ ├── Old │ │ ├── AutoHunt.lua │ │ ├── Territories.lua │ │ ├── json.lua │ │ └── monsters.json │ └── Readme.md ├── Char Cycler.lua ├── GC Supply Scripts │ ├── Auto Gen Provisioning List.lua │ ├── Kupo Box GC Edition.lua │ ├── README.md │ └── Trade GC Items.lua ├── Job Unlocker │ ├── README.md │ └── job unlocker.lua ├── Overseer │ ├── Overseer Launcher.lua │ ├── Overseer.lua │ └── README.md ├── Questionable Companion │ ├── Questionable Companion.lua │ └── README.md ├── Retainer Maker │ ├── README.md │ ├── Retainer Maker CharListGen.lua │ └── Retainer Maker.lua ├── Retired Scripts │ ├── Collect items from main.lua │ ├── Deliver GC Items.lua │ ├── Generate list of items to gather.lua │ ├── README.md │ ├── dol leveller.lua │ ├── recast timers.lua │ └── zone finder.lua ├── Tools │ ├── README.md │ ├── items for fc rank 6.lua │ ├── mail opener.lua │ └── pos finder.lua └── Trading Scripts │ ├── Kupo Box CharListGen.lua │ ├── Kupo Box.lua │ ├── Post Moogle CharListGen.lua │ ├── Post Moogle.lua │ └── README.md ├── template.lua ├── vac_char_list.lua ├── vac_functions.lua └── vac_lists.lua /README.md: -------------------------------------------------------------------------------- 1 | # SND Scripts 2 | 3 | ## Table of Contents 4 | 1. [Introduction](#introduction) 5 | 2. [Prerequisites](#prerequisites) 6 | 3. [Script Categories](#script-categories) 7 | - [GC Supply Scripts](#gc-supply-scripts) 8 | - [Job Unlocker](#job-unlocker) 9 | - [AutoHunt](#autohunt) 10 | - [Overseer](#overseer) 11 | - [Questionable Companion](#questionable-companion) 12 | - [Retainer Maker](#retainer-maker) 13 | - [Tools](#tools) 14 | - [Trading Scripts](#trading-scripts) 15 | - [Character Cycler](#character-cycler) 16 | - [Retired Scripts](#retired-scripts) 17 | 4. [Planned Changes](#planned-changes) 18 | 5. [Installation](#installation) 19 | 6. [License](#license) 20 | 7. [Third-Party Libraries](#third-party-libraries) 21 | 22 | ## Introduction 23 | This repository contains a collection of SND scripts designed to automate various tasks. These scripts enhance efficiency and assist with management tasks, particularly for players managing multiple accounts or FCs. 24 | 25 | Please note that all our scripts disable the `Yes Already` plugin, that means if you stop a script early, the functionality the plugin provides (your own configured `/pyes` settings) will no longer work until you click the button to enable it again, other plugins share this behaviour and is not exclusive to the scripts we provide. 26 | 27 | ## Prerequisites 28 | - All scripts require `vac_functions.lua` and `vac_lists.lua` to be placed in your SND config folder. 29 | - Some scripts may require specific plugins and a minimum plugin version, which will be noted in their respective sections. In addition to this the script will not run until it detects you have the required plugins enabled and at the required version, which will be shown in your chat log. 30 | - Certain scripts require two service accounts to function properly, this will be noted in each script. 31 | - Script functionality will break if you have any "auto actions" enabled in plugins such as auto peloton, please ensure you do not have any conflicting settings. 32 | - Some scripts require the following settings to operate properly, and are handled automatically: 33 | - SND settings: 34 | - `UseSNDTargeting` set to true 35 | - `StopMacroIfActionTimeout` set to false 36 | - `StopMacroIfItemNotFound` set to false 37 | - `StopMacroIfCantUseItem` set to false 38 | - `StopMacroIfTargetNotFound` set to false 39 | - `StopMacroIfAddonNotFound` set to false 40 | - `StopMacroIfAddonNotVisible` set to false 41 | - Simple Tweaks settings: 42 | - `FixTarget` set to true 43 | - `DisableTitleScreenMovie` set to true 44 | - `EquipJobCommand` set to true 45 | - `RecommendEquipCommand` set to true 46 | - CBT settings: 47 | - `MaxGCRank` set to false 48 | - `AutoSnipeQuests` set to true 49 | 50 | ## Script Categories 51 | 52 | ### GC Supply Scripts 53 | ![Status](https://img.shields.io/badge/status-working-brightgreen) 54 | 55 | Automate the process of leveling DoL jobs through GC turn-ins. Requires two service accounts. 56 | 57 | Recommended to not use the Enforce Expert Delivery hack inside CBT plugin. 58 | 59 | | Script Name | Description | Requirements | 60 | |-------------|-------------|--------------| 61 | | `Auto Gen Provisioning List.lua` | Compiles required GC provision supply items and creates a `list_to_gather.txt` file | - | 62 | | `Trade GC Items.lua` | Facilitates item trading between characters | Use with `Kupo Box GC Edition.lua` (optional) | 63 | | `Kupo Box GC Edition.lua` | Automates item delivery to GC, including **Expert Delivery**. Can be used **standalone for turn-ins** without requiring `Trade GC Items.lua`. | - | 64 | 65 | ### Job Unlocker 66 | ![Status](https://img.shields.io/badge/status-broken-red) 67 | 68 | Automates GC-related tasks including hunt logs, quest unlocks, and FC-related actions. This will be remade at some point, and is not as complete as the other scripts. 69 | 70 | ### AutoHunt 71 | ![Status](https://img.shields.io/badge/status-needs_testing-blue) 72 | ![Status](https://img.shields.io/badge/working%3F-probably-aquamarine) 73 | 74 | Does one hunt log of your choice, including dungeon mobs. Currently only tested with Flames 1-2 and Marauder 1. 75 | 76 | 77 | ### Overseer 78 | ![Status](https://img.shields.io/badge/status-needs_testing-blue) 79 | ![Status](https://img.shields.io/badge/working%3F-probably-aquamarine) 80 | 81 | Manages AutoRetainer tasks, including: 82 | - **Automated Backups**: Safeguard your Auto Retainer configuration with backup rotation (up to 50 backups). 83 | - **Submersible Optimisation**: 84 | - Automatic creation and enabling of submersibles. 85 | - Part swapping for optimal voyaging based on submersible rank and configuration, there are submersible and inventory checks to ensure you have the parts. 86 | - Route handling and plan management. 87 | - Optimal vessel behaviour based on number of unlocked submersibles. 88 | - Incorrect submersible route and build corrections. 89 | - **Retainer Optimisation**: 90 | - Plan management. 91 | - **FC Management**: 92 | - GC expert delivery turnins with option for enabling Seal Sweetener I or II buffs. 93 | - Ceruleum Tank purchasing and topup management. 94 | - Venture purchasing and topup management. 95 | - **Silent Operation**: Works seamlessly in the background with no interruptions. 96 | - **Shutdown Timers**: Option to shutdown your client after a specified time for auth token renewal. 97 | - **Menu Bailouts**: Additional menu bailouts for when a menu gets stuck. 98 | 99 | ### Questionable Companion 100 | 101 | ![Status](https://img.shields.io/badge/status-working-brightgreen) 102 | ![Status](https://img.shields.io/badge/bugs%3F-maybe-yellow) 103 | 104 | Enhances the Questionable plugin with features like: 105 | - Automatic duty support dungeon queueing 106 | - Solo instance automation 107 | - Vnavmesh stuck checking 108 | - Death handling 109 | 110 | ### Retainer Maker 111 | ![Status](https://img.shields.io/badge/status-needs_testing-blue) 112 | 113 | Automates the process of creating new retainers. Includes a CharListGen for easy configuration. 114 | 115 | ### Tools 116 | Utility scripts for various tasks: 117 | 118 | | Script Name | Description | Status | 119 | |-------------|-------------|-------------| 120 | | Items for FC Rank 6 | Calculates items needed for FC rank 6 | ![Status](https://img.shields.io/badge/status-working-brightgreen) | 121 | | Mail Opener | Automates mail management | ![Status](https://img.shields.io/badge/status-needs_testing-blue) | 122 | | Pos Finder | Displays and logs current position | ![Status](https://img.shields.io/badge/status-working-brightgreen) | 123 | 124 | ### Trading Scripts 125 | ![Status](https://img.shields.io/badge/status-working-brightgreen) 126 | 127 | Facilitates item trading between multiple characters. Requires two service accounts. 128 | 129 | | Script Name | Description | 130 | |-------------|-------------| 131 | | Kupo Box | Receives items at configured locations | 132 | | Post Moogle | Sends items from configured locations | 133 | 134 | Both include a CharListGen for easy configuration. 135 | 136 | ### Character Cycler 137 | ![Status](https://img.shields.io/badge/status-working-brightgreen) 138 | 139 | Cycles toons and runs a script on each. Meant to be used with alts, like doing the hunt log and some such. 140 | 141 | ### Retired Scripts 142 | ![Status](https://img.shields.io/badge/status-retired-lightgrey) 143 | 144 | Archive of deprecated scripts. No active support provided. 145 | 146 | ## Planned Changes 147 | - Rewriting [Job Unlocker](https://github.com/WigglyMuffin/SNDScripts/tree/main/Scripts/Job%20Unlocker) script 148 | - Rewriting [Questionable Companion](https://github.com/WigglyMuffin/SNDScripts/tree/main/Scripts/Questionable%20Companion) script 149 | - Rewriting [Retainer Maker](https://github.com/WigglyMuffin/SNDScripts/tree/main/Scripts/Retainer%20Maker) script 150 | - Changing plugins from Rotation Solver Reborn to Wrath Combo for auto rotations 151 | - Changing plugins from Teleporter to Lifestream for teleports 152 | - Changing plugins from BossMod Reborn to BossMod for duty solving support 153 | 154 | ## Installation 155 | 1. Verify all required plugins are installed and enabled. 156 | 2. Download the latest vac_functions and vac_lists files. 157 | 3. Place the vac_functions and vac_lists files in your SND config folder (`%appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing`), this location will need to be changed manually in each script if you have a different environment or default location set. 158 | 4. Download the latest script files of your choice from their respective locations. 159 | 5. Place scripts inside your SND environment (`/snd` and import the scripts). 160 | 6. Each script can have a configuration/settings section, ensure that you correctly set it up for your needs. 161 | 162 | ## License 163 | This project is licensed under the [GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.en.html). 164 | 165 | ## Third-Party Libraries 166 | - JSON Library for Lua 167 | - Source: https://github.com/craigmj/json4lua 168 | - License: MIT License 169 | - Full license text included with library code 170 | 171 | *Note: The inclusion of MIT-licensed code does not affect the overall GPL v3 licensing of this project.* 172 | -------------------------------------------------------------------------------- /Scripts/AutoHunt/AutoHuntLog - Helper.lua: -------------------------------------------------------------------------------- 1 | --This needs to go on the party_member that helps you do the dungeons 2 | --Needs to be manually stopped when you're done 3 | 4 | function Sleep(time) 5 | yield("/wait " .. tostring(time)) 6 | end 7 | 8 | function TargetNearestObject(target_name, objectKind, radius) 9 | local smallest_distance = math.huge 10 | local closest_target 11 | local objectKind = objectKind or 0 -- Set objectkind to 0 so GetNearbyObjectNames pulls everything nearby 12 | local radius = radius or 0 13 | local nearby_objects = GetNearbyObjectNames(radius ^ 2, objectKind) -- Pull all nearby objects/enemies into a list 14 | if nearby_objects.Count > 0 then -- Starts a loop if there's more than 0 nearby objects 15 | for i = 0, nearby_objects.Count - 1 do 16 | if nearby_objects.Count > 20 then --This is to prevent crashes, may want to comment it if it works anyway 17 | Sleep(0.0001) 18 | end -- Loops until no more objects 19 | yield("/target " .. nearby_objects[i]) 20 | if not GetTargetName() or nearby_objects[i] ~= GetTargetName() then -- If target name is nil, skip it 21 | elseif GetDistanceToTarget() < smallest_distance and GetTargetName() == target_name then -- If object matches the target_name and the distance to target is smaller than the current smallest_distance, proceed 22 | smallest_distance = GetDistanceToTarget() 23 | closest_target = GetTargetName() 24 | elseif not target_name and GetDistanceToTarget() < smallest_distance then -- If there is no target specified, return closest anything 25 | smallest_distance = GetDistanceToTarget() 26 | closest_target = GetTargetName() 27 | end 28 | end 29 | ClearTarget() 30 | if closest_target then yield("/target " .. closest_target) end -- after the loop ends it targets the closest enemy 31 | end 32 | return closest_target 33 | end 34 | 35 | function GetDutyInfoText(pos) 36 | local function GetDutyInfoStartingNode() 37 | for i=8, 12 do 38 | if IsNodeVisible("_ToDoList", 1, (70013-i)) then 39 | return (39-2*i) 40 | end 41 | end 42 | return 13 43 | end 44 | local starting_node = GetDutyInfoStartingNode() 45 | if not pos then 46 | return 47 | end 48 | local text = GetNodeText("_ToDoList", (starting_node+pos-1), 3) 49 | return text 50 | end 51 | 52 | function LeaveDuty() 53 | while GetCharacterCondition(34) do 54 | if IsAddonReady("SelectYesno") then 55 | yield("/callback SelectYesno true 0") 56 | elseif IsAddonVisible("ContentsFinderMenu") then 57 | yield("/callback ContentsFinderMenu true 0") 58 | else 59 | yield("/dutyfinder") 60 | end 61 | Sleep(0.1) 62 | end 63 | end 64 | 65 | function GetDutyTimer() 66 | if not GetCharacterCondition(34) and not GetCharacterCondition(56) then 67 | LogInfo("[VAC] GetDutyTimer(): You're not in a duty.") 68 | return 69 | end 70 | local function GetDutyTimerTextNode() 71 | for i=8, 12 do 72 | if IsNodeVisible("_ToDoList", 1, (70013-i)) then 73 | 74 | return (23-i) 75 | end 76 | end 77 | return 10 78 | end 79 | local duty_timer_node = GetDutyTimerTextNode() 80 | local duty_timer_text = GetNodeText("_ToDoList", duty_timer_node, 8) 81 | local minutes, seconds = duty_timer_text:match("^(%d+):(%d+)$") 82 | local duty_timer_seconds = tonumber(minutes) * 60 + tonumber(seconds) 83 | return duty_timer_seconds 84 | end 85 | 86 | repeat 87 | while not IsPlayerAvailable() do 88 | Sleep(1.0534) 89 | end 90 | if DoesObjectExist("Magitek Transporter") then --try to move if AD path is running ahead 91 | TargetNearestObject("Magitek Transporter", 7, 10) 92 | if GetTargetName() == "Magitek Transporter" and current_x == GetPlayerRawXPos() and current_z == GetPlayerRawZPos() then 93 | yield("/ad pause") 94 | yield("/vnav moveto " .. GetTargetRawXPos() .. " " .. GetTargetRawYPos() .. " " .. GetTargetRawZPos()) 95 | repeat 96 | Sleep(0.1) 97 | until GetDistanceToTarget() < 2 98 | yield("/interact") 99 | Sleep(0.5) 100 | while IsAddonReady("SelectYesno") do 101 | yield("/callback SelectYesno true 0") 102 | Sleep(0.0956) 103 | end 104 | yield("/ad resume") 105 | end 106 | end 107 | local duty_timer = GetDutyTimer() 108 | local Terminal_List = { 109 | [1] = { 110 | ["Name"] = "III", 111 | ["Coords"] = "124 -13.8 123.4" 112 | }, 113 | [2] = { 114 | ["Name"] = "IV", 115 | ["Coords"] = "140.75 -12 113.2" 116 | }, 117 | [3] = { 118 | ["Name"] = "IX", 119 | ["Coords"] = "-14.9 -21 -143.97" 120 | }, 121 | [4] = { 122 | ["Name"] = "VIII", 123 | ["Coords"] = "-16.22 -17.3 -177.55" 124 | } 125 | } 126 | for i=1, #Terminal_List do 127 | if GetToastNodeText(2, 3) == "Magitek terminal "..Terminal_List[i]["Name"].." begins counting down." then 128 | local counter = 0 129 | repeat 130 | ClearTarget() 131 | yield("/vnav moveto "..Terminal_List[i]["Coords"]) 132 | Sleep(0.22) 133 | counter = counter+1 134 | until GetToastNodeText(2, 3) == "Magitek terminal "..Terminal_List[i]["Name"].."'s countdown completes." or counter > 200 135 | end 136 | end 137 | if duty_timer and duty_timer < 4950 and GetDutyInfoText(2) == "Clear the feasting hall: 1/1" and GetToastNodeText(2, 3) == "Magitek terminal "..Terminal_List[3]["Name"].."'s countdown completes." then 138 | yield("/vnav moveto "..Terminal_List[4]["Coords"]) 139 | elseif duty_timer and duty_timer < 5010 and GetDutyInfoText(2) == "Clear the feasting hall: 1/1" and not GetDutyInfoText(4) == "Defeat Batraal: 0/1" then 140 | yield("/vnav moveto "..Terminal_List[3]["Coords"]) 141 | elseif GetDutyInfoText(2) == "Clear the feasting hall: 0/1" and GetTargetName() == "All-seeing Eye" then 142 | local Crystal_Coords = { 143 | [1] = { 144 | ["x"] = 74.6, 145 | ["y"] = -13.4, 146 | ["z"] = 83.0 147 | }, 148 | [2] = { 149 | ["x"] = 21.6, 150 | ["y"] = -14.2, 151 | ["z"] = 90.9 152 | }, 153 | [3] = { 154 | ["x"] = 48.8, 155 | ["y"] = -11.6, 156 | ["z"] = 116.0 157 | }, 158 | [4] = { 159 | ["x"] = 15.3, 160 | ["y"] = -9.5, 161 | ["z"] = 46.7 162 | } 163 | } 164 | yield("/ad pause") 165 | local crystal = 1 166 | while DoesObjectExist("All-seeing Eye") do 167 | yield("/vnav moveto "..Crystal_Coords[crystal]["x"].." "..Crystal_Coords[crystal]["y"].." "..Crystal_Coords[crystal]["z"]) 168 | if not HasStatus("Crystal Veil") and current_x and current_z and current_x^2 + current_z^2 < 1 then 169 | crystal=crystal+1 170 | if crystal == 5 then 171 | crystal = 1 172 | end 173 | else 174 | while TargetHasStatus(325)==true and HasStatus("Crystal Veil") do 175 | yield("/vnav moveto "..Crystal_Coords[crystal]["x"].." "..Crystal_Coords[crystal]["y"].." "..Crystal_Coords[crystal]["z"]) 176 | Sleep(1.34) 177 | end 178 | end 179 | Sleep(1.37) 180 | end 181 | yield("/ad resume") 182 | elseif GetDutyInfoText(1) == "Open the grand hall gate: 0/1" and (GetToastNodeText(2, 3) == "Magitek terminal "..Terminal_List[1]["Name"].."'s countdown completes." or (duty_timer and duty_timer < 5220)) then 183 | yield("/vnav moveto "..Terminal_List[2]["Coords"]) 184 | elseif duty_timer and duty_timer < 5280 and GetDutyInfoText(1) == "Open the grand hall gate: 0/1" then 185 | yield("/vnav moveto "..Terminal_List[1]["Coords"]) 186 | end 187 | if duty_timer and duty_timer < 4200 then 188 | yield("/ad stop") 189 | LeaveDuty() 190 | end 191 | current_x = GetPlayerRawXPos() 192 | current_z = GetPlayerRawZPos() 193 | Sleep(2) 194 | until forever 195 | -------------------------------------------------------------------------------- /Scripts/AutoHunt/Readme.md: -------------------------------------------------------------------------------- 1 | ## AutoHunt (formerly Hunt Log Doer) 2 | 3 | ### IF YOU HAVE AN ISSUE, MAKE SURE YOU ARE ON SND TESTING v12.0.0.0 and both scripts are up to date! I, Friendly (ping me) <AutoParty>, will try to help with bugs but that will be my first question so don't be a dum-dum and do that first. Don't ping Wiggly for this script. 4 | 5 | Original by CacahuetesManu https://github.com/CacahuetesManu/SND/tree/main/Hunt%20Log%20Doer 6 | 7 | An SND script to automate the hunt log for a given class/GC and rank. Goes to home/inn after. 8 | If doing GC log, it's recommended that you're lvl 50. There's an option to unlock SAM for iLvl 110 gear. 9 | Does dungeon mobs for GC logs, with an option to invite a helper character and leave duty after completing log. 10 | Does GC rankups, will try to exchange seals if that's preventing you from ranking up and complete all dungeons needed for rank 9 (for duck bones, oilcloth, etc.). 11 | No extra files needed, just check the configs/requirements in the script. 12 | 13 | If you find a bug in the script and it's not in the list below, feel free to report it. 14 | 15 | ****************** 16 | * Improvements * 17 | ****************** 18 | Class hunt logs aren't all tested. 19 | It spams "You need to finish the quest [insert quest name] to rank up more". 20 | If you wanna contribute, feel free, but I need to move on with my life. 21 | 22 | You can help with mob positions without knowing how to code. If the script gets stuck, manually go the position you should go for this mob (try to have as many within range as possible). 23 | Get coordinates from eg. Questionable plugin (see pic) and either make a PR here or send me the mob and coords on discord (Friendly (ping me) <AutoParty> on Punish). 24 | 25 | ![image](https://github.com/user-attachments/assets/ee348812-3d1f-4581-b731-07ec9093c954) 26 | 27 | # Misc 28 | The old version requires all files in that folder. MAKE SURE TO TELL SND WHERE THEY ARE (SND HELP --> OPTIONS --> LUA) 29 | Make sure to set up your paths. Use the Lua path setting in the SND help config. 30 | 31 | C:\\Users\\Username\\AppData\\Roaming\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing 32 | 33 | Like this: ![LuaPaths](https://github.com/user-attachments/assets/3e31a761-8e70-4d66-867a-b8bf762401d7) 34 | -------------------------------------------------------------------------------- /Scripts/Char Cycler.lua: -------------------------------------------------------------------------------- 1 | --[[####################################### 2 | ## Character Cycler ## 3 | ## by Friendly ## 4 | ## ## 5 | ## made with WigglyMuffin functions ## 6 | ########################################### 7 | 8 | #################################################### 9 | ## Description ## 10 | #################################################### 11 | 12 | -- This script cycles through characters and runs scripts per char and/or a full cycle 13 | -- Run retainers "without" AR, do quests or turnin on alts, etc. The sky is the limit. 14 | -- Can operate continuously if you put this script's name as cycle_script_name 15 | -- Get vac_char_list.lua and vac_functions.lua from https://github.com/WigglyMuffin/SNDScripts 16 | -- put them in your SND config folder: %appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing (can copy and paste this in Windows) 17 | 18 | -- ########### 19 | -- # CONFIGS # 20 | -- #########]] 21 | 22 | local use_external_character_list = true -- Options: true = uses the external character list in the same folder, default name being char_list.lua, false uses the list you put in this file 23 | char_script_name = "" -- name of script to run after each character 24 | cycle_script_name = "" -- name of script to run once this script finishes 25 | return_location = "auto" -- where toons go after running script. same as using /li return_location 26 | pause_yesalready = false -- pause YesAlready while script is running 27 | 28 | --[[ This is where you put your character list if you choose to NOT use the external one 29 | -- If use_external_character_list is set to true then this list is completely skipped 30 | -- Can start from current toon and go to the end of the list (!!when gameobject is fixed again) 31 | -- Add your toons here or external list like so 32 | 33 | local character_list = { 34 | "Example Character@Server", 35 | "John Doe@Balmung", 36 | } 37 | ]] 38 | 39 | local character_list = { 40 | } 41 | 42 | -- ##################################### 43 | -- # DON'T TOUCH ANYTHING BELOW HERE # 44 | -- # UNLESS YOU KNOW WHAT YOU'RE DOING # 45 | -- ##################################### 46 | 47 | char_list = "vac_char_list.lua" 48 | 49 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 50 | vac_config_folder = snd_config_folder .. "\\VAC\\" 51 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 52 | LoadFunctions = loadfile(load_functions_file_location) 53 | LoadFunctions() 54 | LoadFileCheck() 55 | 56 | if not CheckPluginsEnabled("AutoRetainer", "TeleporterPlugin", "Lifestream", "PandorasBox", "SomethingNeedDoing", "TextAdvance", "vnavmesh", "YesAlready") then 57 | return -- Stops script as plugins not available 58 | end 59 | 60 | if HasPlugin("YesAlready") and pause_yesalready then 61 | PauseYesAlready() 62 | end 63 | 64 | yield("/ays m d")-- if started during multi 65 | yield("/ays d") 66 | yield("/ays reset") 67 | 68 | LogInfo("[CC] ##############################") 69 | LogInfo("[CC] Starting script...") 70 | LogInfo("[CC] snd_config_folder: " .. snd_config_folder) 71 | LogInfo("[CC] char_list: " .. char_list) 72 | LogInfo("[CC] SNDConf+Char: " .. snd_config_folder .. "" .. char_list) 73 | LogInfo("[CC] ##############################") 74 | 75 | if use_external_character_list then 76 | local char_data = dofile(snd_config_folder .. char_list) 77 | character_list = char_data.character_list 78 | end 79 | 80 | 81 | function RelogAndDoThing() 82 | -- Find the index of current character in the list 83 | local start_index = -1 84 | for i, char in ipairs(character_list) do 85 | if GetCharacterName(true) == char then 86 | start_index = i 87 | LogInfo("[CC] Starting from character: " .. char .. " at index " .. start_index) 88 | break 89 | end 90 | end 91 | if start_index == -1 then -- Character not found in the list, start from 1 92 | if #character_list == 0 then 93 | LogInfo("[CC] No characters found in your char_list.") 94 | return 95 | end 96 | yield("/ays relog " .. character_list[1]) 97 | Sleep(23.0) 98 | LoginCheck() 99 | end 100 | -- Loop through char_list once starting from current toon 101 | for i = 0, #character_list - 1 do 102 | -- Calculate the actual index with wrap-around 103 | local actual_index = ((start_index + i - 1) % #character_list) + 1 104 | local char = character_list[actual_index] 105 | 106 | LogInfo("[CC] Processing char number " .. actual_index) 107 | 108 | if GetCharacterName(true) == char then 109 | LogInfo("[CC] Already on the right character: " .. char) 110 | else 111 | LogInfo("[CC] Logging into: " .. char) 112 | RelogCharacter(char) 113 | Sleep(7.5) --This is enough time to log out completely and not too long to cut into new logins 114 | --LoginCheck() --!!replacing with below repeat till gameobject fix 115 | for j = 1, 500 do 116 | Sleep(0.5) 117 | if IsPlayerAvailable() and IsAddonVisible("NamePlate") then 118 | break 119 | end 120 | end 121 | end 122 | 123 | --Run the script for the current character 124 | yield("/at e") --strangely TextAdvance turns off sometimes 125 | yield("/snd run " .. char_script_name) 126 | Sleep(1) -- this is needed for the script to start 127 | Teleporter(return_location, "li") 128 | Sleep(3) 129 | end 130 | end 131 | 132 | RelogAndDoThing() 133 | Sleep(1) --just in case, may not be needed 134 | if HasPlugin("YesAlready") and pause_yesalready then 135 | RestoreYesAlready() 136 | end 137 | yield("/snd run "..cycle_script_name) -------------------------------------------------------------------------------- /Scripts/GC Supply Scripts/Auto Gen Provisioning List.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | _ _____ _____ _ _ _ _ _ _ 3 | /\ | | / ____| | __ \ (_) (_) (_) | | (_) | | 4 | / \ _ _| |_ ___ | | __ ___ _ __ | |__) | __ _____ ___ ___ _ ___ _ __ _ _ __ __ _ | | _ ___| |_ 5 | / /\ \| | | | __/ _ \ | | |_ |/ _ \ '_ \ | ___/ '__/ _ \ \ / / / __| |/ _ \| '_ \| | '_ \ / _` | | | | / __| __| 6 | / ____ \ |_| | || (_) | | |__| | __/ | | | | | | | | (_) \ V /| \__ \ | (_) | | | | | | | | (_| | | |____| \__ \ |_ 7 | /_/ \_\__,_|\__\___/ \_____|\___|_| |_| |_| |_| \___/ \_/ |_|___/_|\___/|_| |_|_|_| |_|\__, | |______|_|___/\__| 8 | __/ | 9 | |___/ 10 | 11 | #################### 12 | ## Version ## 13 | ## 1.0.2 ## 14 | #################### 15 | 16 | -> 1.0.0: Initial release 17 | -> 1.0.1: Duplicate name across worlds fix 18 | -> 1.0.2: Merged Auto Gen Provisioning List script with Generate list of items to gather script 19 | 20 | #################################################### 21 | ## Description ## 22 | #################################################### 23 | 24 | https://github.com/WigglyMuffin/SNDScripts 25 | 26 | This script will automatically cycle through your characters and generate a list of items needed for GC supply 27 | A list will be generated and output to the SND config folder saved as a file (provisioning_list.lua) 28 | Which will be used to create another file (list_to_gather.txt) to show which items are needed for the rest of the scripts to function 29 | 30 | Edit vac_char_list.lua (character_list) for configuring characters if using an external list 31 | 32 | #################################################### 33 | ## Requirements ## 34 | #################################################### 35 | 36 | -> AutoRetainer : https://love.puni.sh/ment.json 37 | -> Lifestream : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 38 | -> Something Need Doing (Expanded Edition) : https://puni.sh/api/repository/croizat 39 | -> Teleporter : In the default first party dalamud repository 40 | -> TextAdvance : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 41 | -> vnavmesh : https://puni.sh/api/repository/veyn 42 | 43 | #################################################### 44 | ## Settings ## 45 | ##################################################]] 46 | 47 | local level_cap = 100 -- Job level cap, adjust according to your current level cap 48 | local skip_level_capped_jobs = true -- Options: true = Will skip level capped jobs, false = Will not skip level capped jobs 49 | local min_enabled = true -- Options: true = Will store MIN items, false = Will skip MIN items 50 | local btn_enabled = true -- Options: true = Will store BTN items, false = Will skip BTN items 51 | local fsh_enabled = true -- Options: true = Will store FSH items, false = Will skip FSH items 52 | 53 | -- Options: true = Uses the external character list in the same folder, default name being char_list.lua, false = Uses the list you put in this file 54 | local use_external_character_list = true 55 | 56 | -- This is where you put your character list if you choose to not use the external one 57 | -- If use_external_character_list is set to true then this list is completely skipped 58 | local character_list = { 59 | "First Last@Server", 60 | "First Last@Server" 61 | } 62 | 63 | --[[################################################ 64 | ## Script Start ## 65 | ##################################################]] 66 | 67 | char_list = "vac_char_list.lua" 68 | provisioning_list_save_name = "provisioning_list.lua" 69 | 70 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 71 | vac_config_folder = snd_config_folder .. "\\VAC\\" 72 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 73 | LoadFunctions = loadfile(load_functions_file_location)() 74 | LoadFileCheck() 75 | 76 | -- Plugin checker 77 | local required_plugins = { 78 | AutoRetainer = "4.4.4", 79 | TeleporterPlugin = "2.0.2.5", 80 | Lifestream = "2.3.2.8", 81 | SomethingNeedDoing = "1.75", 82 | TextAdvance = "3.2.4.4", 83 | vnavmesh = "0.0.0.54" 84 | } 85 | 86 | if not CheckPlugins(required_plugins) then 87 | return -- Stops script as plugins not available or versions don't match 88 | end 89 | 90 | if HasPlugin("YesAlready") then 91 | PauseYesAlready() 92 | end 93 | 94 | LogInfo("[APL] ##############################") 95 | LogInfo("[APL] Starting script...") 96 | LogInfo("[APL] snd_config_folder: " .. snd_config_folder) 97 | LogInfo("[APL] char_list: " .. char_list) 98 | LogInfo("[APL] SNDConf+Char: " .. snd_config_folder .. "" .. char_list) 99 | LogInfo("[APL] provisioning_list_save_name: " .. provisioning_list_save_name) 100 | LogInfo("[APL] SNDConf+PROV: " .. snd_config_folder .. "" .. provisioning_list_save_name) 101 | LogInfo("[APL] ##############################") 102 | 103 | local gc_config_folder = vac_config_folder .. "\\GC\\" 104 | EnsureFolderExists(gc_config_folder) 105 | 106 | if use_external_character_list then 107 | local char_data = dofile(snd_config_folder .. char_list) 108 | character_list = char_data.character_list 109 | end 110 | 111 | local provisioning_list = {} 112 | 113 | function FindGCItemID(item_name) 114 | local lists = { 115 | GC_MIN_List = "GC_MIN_List", 116 | GC_BTN_List = "GC_BTN_List", 117 | GC_FSH_List = "GC_FSH_List" 118 | } 119 | 120 | for list, list_name in pairs(lists) do 121 | if _G[list][item_name] then 122 | return _G[list][item_name].ID, list_name 123 | end 124 | end 125 | 126 | return 0, "Not found" 127 | end 128 | 129 | function SerializeTable(val, name, depth) 130 | depth = depth or 0 131 | local result = "" 132 | local indent = string.rep(" ", depth) 133 | 134 | if name then 135 | result = result .. indent .. name .. " = " 136 | end 137 | 138 | if type(val) == "table" then 139 | result = result .. "{\n" 140 | 141 | for k, v in pairs(val) do 142 | local key 143 | 144 | if type(k) == "string" then 145 | key = string.format("[%q]", k) 146 | else 147 | key = "[" .. k .. "]" 148 | end 149 | 150 | result = result .. SerializeTable(v, key, depth + 1) .. ",\n" 151 | end 152 | result = result .. indent .. "}" 153 | elseif type(val) == "string" then 154 | result = result .. string.format("%q", val) 155 | elseif type(val) == "number" or type(val) == "boolean" then 156 | result = result .. tostring(val) 157 | else 158 | error("Unsupported data type: " .. type(val)) 159 | end 160 | 161 | return result 162 | end 163 | 164 | function GetAndSaveProvisioningToTable() 165 | for i, char in ipairs(character_list) do 166 | LogInfo("[APL] Processing char number " .. i) 167 | 168 | if GetCharacterName(true) == char then 169 | LogInfo("[APL] Already on the right character: " .. char) 170 | else 171 | LogInfo("[APL] Logging into: " .. char) 172 | 173 | if not InSanctuary() then 174 | Teleporter("Limsa Lominsa Lower Decks", "tp") 175 | end 176 | 177 | RelogCharacter(char) 178 | Sleep(7.5) -- This is enough time to log out completely and not too long to cut into new logins 179 | LoginCheck() 180 | end 181 | 182 | local char_name = GetCharacterName() .. "@" .. FindWorldByID(GetHomeWorld()) 183 | 184 | repeat 185 | Sleep(0.1) 186 | until IsPlayerAvailable() 187 | 188 | local min_level = GetPlayerJobLevel("MIN") 189 | local btn_level = GetPlayerJobLevel("BTN") 190 | local fsh_level = GetPlayerJobLevel("FSH") 191 | OpenTimers() 192 | Sleep(1.0) 193 | 194 | function ContainsLetters(input) 195 | if input:match("%a") then 196 | return true 197 | else 198 | return false 199 | end 200 | end 201 | 202 | local Row1ItemName = GetNodeText("ContentsInfoDetail", 101, 5) 203 | LogInfo("[APL] " .. tostring(Row1ItemName)) 204 | LogInfo("[APL] " .. tostring(ContainsLetters(Row1ItemName))) 205 | provisioning_list[char_name] = {} 206 | 207 | for i = 101, 99, -1 do 208 | local ItemName = GetNodeText("ContentsInfoDetail", i, 5) 209 | if ContainsLetters(ItemName) then 210 | LogInfo("[APL] " .. ItemName .. " Row text found") 211 | else 212 | LogInfo("[APL] Row text not found") 213 | break 214 | end 215 | LogInfo("[APL] Inserting from row") 216 | local ItemID, ListName = FindGCItemID(ItemName) 217 | local ItemAmount = GetNodeText("ContentsInfoDetail", i, 2) 218 | 219 | if ListName == "GC_MIN_List" then 220 | if min_enabled and (min_level < level_cap or (min_level >= level_cap and not skip_level_capped_jobs)) then 221 | provisioning_list[char_name]["MIN"] = {} 222 | provisioning_list[char_name]["MIN"]["Item"] = ItemName 223 | provisioning_list[char_name]["MIN"]["ID"] = ItemID 224 | provisioning_list[char_name]["MIN"]["QTY"] = ItemAmount 225 | end 226 | elseif ListName == "GC_BTN_List" then 227 | if btn_enabled and (btn_level < level_cap or (btn_level >= level_cap and not skip_level_capped_jobs)) then 228 | provisioning_list[char_name]["BTN"] = {} 229 | provisioning_list[char_name]["BTN"]["Item"] = ItemName 230 | provisioning_list[char_name]["BTN"]["ID"] = ItemID 231 | provisioning_list[char_name]["BTN"]["QTY"] = ItemAmount 232 | end 233 | elseif ListName == "GC_FSH_List" then 234 | if fsh_enabled and (fsh_level < level_cap or (fsh_level >= level_cap and not skip_level_capped_jobs)) then 235 | provisioning_list[char_name]["FSH"] = {} 236 | provisioning_list[char_name]["FSH"]["Item"] = ItemName 237 | provisioning_list[char_name]["FSH"]["ID"] = ItemID 238 | provisioning_list[char_name]["FSH"]["QTY"] = ItemAmount 239 | end 240 | end 241 | end 242 | 243 | if not provisioning_list[char_name]["MIN"] and not provisioning_list[char_name]["BTN"] and not provisioning_list[char_name]["FSH"] then 244 | provisioning_list[char_name] = nil 245 | else 246 | local CharHomeWorld = FindWorldByID(GetHomeWorld()) 247 | provisioning_list[char_name]["CharHomeWorld"] = CharHomeWorld 248 | end 249 | 250 | local provisioning_list_strings = "provisioning_list = " .. SerializeTable(provisioning_list) 251 | local filepath = gc_config_folder .. provisioning_list_save_name 252 | local File = io.open(filepath, "w") 253 | File:write(provisioning_list_strings) 254 | File:close() 255 | end 256 | end 257 | 258 | -- Generate list of items to gather 259 | function GenerateGCFile() 260 | provisioning_list_name_to_load = "provisioning_list.lua" 261 | 262 | local gc_config_folder = vac_config_folder .. "\\GC\\" 263 | dofile(gc_config_folder .. provisioning_list_name_to_load) 264 | 265 | local output_filename = "list_to_gather.txt" 266 | local output_folder = gc_config_folder 267 | 268 | EnsureFolderExists(output_folder) 269 | 270 | local function combine_items_by_category(provisioning_list) 271 | local category_totals = {} 272 | 273 | local category_names = { 274 | MIN = "Miner", 275 | BTN = "Botanist", 276 | FSH = "Fisher" 277 | } 278 | 279 | for _, data in pairs(provisioning_list) do 280 | for category, item_data in pairs(data) do 281 | if type(item_data) == "table" and item_data["Item"] then 282 | local item_name = item_data["Item"] 283 | local item_qty = tonumber(item_data["QTY"]) 284 | local category_name = category_names[category] or category 285 | 286 | if not category_totals[category_name] then 287 | category_totals[category_name] = {} 288 | end 289 | 290 | if not category_totals[category_name][item_name] then 291 | category_totals[category_name][item_name] = 0 292 | end 293 | 294 | category_totals[category_name][item_name] = category_totals[category_name][item_name] + item_qty 295 | end 296 | end 297 | end 298 | 299 | return category_totals 300 | end 301 | 302 | local function create_character_summary(provisioning_list) 303 | local summaries = {} 304 | 305 | for character_name, data in pairs(provisioning_list) do 306 | local character_summary = {} 307 | for category, item_data in pairs(data) do 308 | if type(item_data) == "table" and item_data["Item"] then 309 | table.insert(character_summary, item_data["Item"] .. ": " .. item_data["QTY"]) 310 | end 311 | end 312 | summaries[character_name] = character_summary 313 | end 314 | 315 | return summaries 316 | end 317 | 318 | local function write_to_file(category_totals, character_summaries, filename) 319 | local file = io.open(filename, "w") 320 | if not file then 321 | return 322 | end 323 | 324 | file:write("************************\n") 325 | file:write("* Provisioning Summary *\n") 326 | file:write("************************\n\n") 327 | 328 | -- Job ordering 329 | local job_order = { "Miner", "Botanist", "Fisher" } 330 | local remaining_categories = {} 331 | 332 | -- Separate order categories and gather remaining ones 333 | for category in pairs(category_totals) do 334 | if not table.concat(job_order):find(category) then 335 | table.insert(remaining_categories, category) 336 | end 337 | end 338 | 339 | -- Sort remaining categories a-z 340 | table.sort(remaining_categories) 341 | 342 | -- Combine ordered categories with the sorted remaining ones 343 | local sorted_categories = {} 344 | 345 | for _, category in ipairs(job_order) do 346 | if category_totals[category] then 347 | table.insert(sorted_categories, category) 348 | end 349 | end 350 | 351 | for _, category in ipairs(remaining_categories) do 352 | table.insert(sorted_categories, category) 353 | end 354 | 355 | -- Write categories to file 356 | for _, category in ipairs(sorted_categories) do 357 | local items = category_totals[category] 358 | file:write(category .. "\n") 359 | file:write(string.rep("=", #category + 4) .. "\n") 360 | 361 | -- Sort items a-z 362 | local sorted_items = {} 363 | 364 | for item in pairs(items) do 365 | table.insert(sorted_items, item) 366 | end 367 | table.sort(sorted_items) 368 | 369 | for _, item in ipairs(sorted_items) do 370 | local qty = items[item] 371 | file:write(item .. ": " .. qty .. "\n") 372 | end 373 | file:write("\n") 374 | end 375 | 376 | file:write("******************************\n") 377 | file:write("* Per Character Requirements *\n") 378 | file:write("******************************\n\n") 379 | 380 | -- Sort character names a-z 381 | local sorted_characters = {} 382 | 383 | for character_name in pairs(character_summaries) do 384 | table.insert(sorted_characters, character_name) 385 | end 386 | table.sort(sorted_characters) 387 | 388 | for _, character_name in ipairs(sorted_characters) do 389 | local summary = character_summaries[character_name] 390 | file:write(character_name .. "\n") 391 | file:write(string.rep("-", #character_name + 4) .. "\n") 392 | 393 | for _, item_line in ipairs(summary) do 394 | file:write(item_line .. "\n") 395 | end 396 | file:write("\n") 397 | end 398 | 399 | file:close() 400 | end 401 | 402 | local combined_items_by_category = combine_items_by_category(provisioning_list) 403 | local character_summaries = create_character_summary(provisioning_list) 404 | 405 | write_to_file(combined_items_by_category, character_summaries, output_folder .. output_filename) 406 | end 407 | 408 | function Main() 409 | -- Auto Gen Provisioning List 410 | GetAndSaveProvisioningToTable() 411 | 412 | -- Generate list of items to gather 413 | GenerateGCFile() 414 | end 415 | 416 | Main() 417 | 418 | if HasPlugin("YesAlready") then 419 | RestoreYesAlready() 420 | end -------------------------------------------------------------------------------- /Scripts/GC Supply Scripts/Kupo Box GC Edition.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | _ __ ____ ____ ____ _____ _ _ _ _ 3 | | |/ / _ _ __ ___ | __ ) _____ __ / ___|/ ___| | ____|__| (_) |_(_) ___ _ __ 4 | | ' / | | | '_ \ / _ \ | _ \ / _ \ \/ / | | _| | | _| / _` | | __| |/ _ \| '_ \ 5 | | . \ |_| | |_) | (_) | | |_) | (_) > < | |_| | |___ | |__| (_| | | |_| | (_) | | | | 6 | |_|\_\__,_| .__/ \___/ |____/ \___/_/\_\ \____|\____| |_____\__,_|_|\__|_|\___/|_| |_| 7 | |_| 8 | 9 | #################### 10 | ## Version ## 11 | ## 1.2.2 ## 12 | #################### 13 | 14 | -> 1.0.0: Initial release 15 | -> 1.0.1: GC Edition of Kupo Box tailored for GC Supply Script series 16 | -> 1.0.2: Movement distance fix for trading distance 17 | -> 1.0.3: Added checks to do_rankups and expert_delivery 18 | -> 1.1.0: 19 | - Option to do turnins only without trade added 20 | - Refactored how skip characters are processed 21 | - Added toggle to enable AR multi mode at end of script 22 | -> 1.2.0: Refactored return_location, will now accept aetheryte locations as well as Lifestream options 23 | -> 1.2.1: Refactored destination_type and destination_house 24 | -> 1.2.2: Fixed incorrect name used for TeleportType() 25 | 26 | #################################################### 27 | ## Description ## 28 | #################################################### 29 | 30 | https://github.com/WigglyMuffin/SNDScripts 31 | 32 | This is the GC Edition of Kupo Box script and it automates a list of characters picking up items from a specified character 33 | It is to be used with the GC Supply Scripts series only, it is not compatible with any other script 34 | 35 | Edit vac_char_list.lua (character_list) for configuring characters if using an external list 36 | 37 | #################################################### 38 | ## Requirements ## 39 | #################################################### 40 | 41 | -> AutoRetainer : https://love.puni.sh/ment.json 42 | -> Teleporter : In the default first party dalamud repository 43 | -> Lifestream : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 44 | -> TextAdvance : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 45 | -> Something Need Doing (Expanded Edition) : https://puni.sh/api/repository/croizat 46 | -> vnavmesh : https://puni.sh/api/repository/veyn 47 | -> Dropbox : https://puni.sh/api/repository/kawaii 48 | -> Recommended settings in dropbox are 4 frames delay between trades and 1500ms trade open command throttle. (Ctrl + left click to specify exact values). 49 | -> You need to enable "Enable auto-accept trades." under the dropbox settings for receiving items. 50 | -> Dropbox UI is required to be visible and on the "Item Trade Queue" tab for trading functionality to operate for giving items. 51 | 52 | Optional plugins: 53 | -> Deliveroo : https://plugins.carvel.li/ 54 | -> Only required if expert_delivery is set to true 55 | 56 | #################################################### 57 | ## Settings ## 58 | #################################################### 59 | 60 | Edit vac_char_list.lua file for configuring characters (character_list), these are the characters you want to do turnins on 61 | 62 | The settings below will be used on all characters set in the character_list 63 | You only need to set these here and you do not need to use the character_list_kupobox, or the CharListGen for Kupo Box ]] 64 | 65 | local trading_with = "Smol Meow" -- Name of the character you are trading with, do not include world 66 | local destination_server = "Sephirot" -- Server characters need to travel to for collecting items 67 | local destination_type = 0 -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 68 | local destination_aetheryte = "Aleport" -- Aetheryte that characters need to travel to for collecting items, case insensitive and you can be vague 69 | local destination_house = 0 -- Options: 0 = FC, 1 = Personal, 2 = Apartment 70 | local do_movement = true -- Options: true = Paths to chosen character, false = Does nothing and waits for chosen character to come to you 71 | local return_home = true -- Options: true = Returns home from destination, false = Does nothing and logs out 72 | local return_location = "" -- Set the return location for each character after tasks are complete, leave empty for no return location (will log out instead) 73 | -- Compatible with most Lifestream options too, such as "auto", "gc", "island" etc. 74 | 75 | -- Options: true = invites character you are trading with to party for trading, false = uses distance based proximity check for trading 76 | -- Setting this to false will result in faster trades (marginally) but is less safe, recommended to set to true 77 | local party_invite = true 78 | 79 | -- In case something goes wrong, you can set the amount of characters in the list to skip, this goes from the top of the list 80 | -- A good way to know how many chars you need to skip is to read the processing echo in chat which lists how many chars have finished already and which char is currently being processed 81 | local skip_chars = 0 -- Number of characters you want to skip 82 | 83 | -- Options: true = Automatically attempts to rank up your GC, false = Do nothing 84 | -- Requires the "Enforce Expert Delivery" option to be disabled in CBT plugin otherwise rank ups will not work properly 85 | local do_rankups = true 86 | 87 | -- Options: true = Will start Deliveroo expert delivery after GC supply turnins, false = Do nothing 88 | -- Requires Deliveroo plugin to be installed and will run expert deliveries after GC turnins 89 | -- Deliveroo needs to be setup properly beforehand 90 | -- Will check if your character has the rank to do expert deliveries, so even if your character does not have the rank leaving it set to true is safe 91 | -- Expert Delivery rank check will be skipped if CBT "Enforce Expert Delivery" option is enabled 92 | local expert_delivery = false 93 | 94 | -- Options: true = Will do GC supply turnins only and not trade, false = Will trade for items and then do GC supply turnins 95 | -- Useful if you have a surplus of items on your characters and do not wish to trade for items each day 96 | local turnins_only = false 97 | 98 | -- Options: true = Will enable AR multi mode at end of script, false = Do nothing 99 | local do_ays_multi = false 100 | 101 | -- Options: true = Uses the external character list (char_list.lua), false = Uses the list you put in this file (character_list) 102 | local use_external_character_list = true 103 | 104 | -- This is where you put your character list if you choose to not use the external one 105 | -- If use_external_character_list is set to true then this list is completely skipped 106 | local character_list = { 107 | "First Last@Server", 108 | "First Last@Server" 109 | } 110 | 111 | --[[################################################ 112 | ## Script Start ## 113 | ##################################################]] 114 | 115 | -- Edit char_list.lua file (character_list) for configuring characters 116 | char_list = "vac_char_list.lua" 117 | 118 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 119 | vac_config_folder = snd_config_folder .. "\\VAC\\" 120 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 121 | LoadFunctions = loadfile(load_functions_file_location)() 122 | LoadFileCheck() 123 | 124 | if use_external_character_list then 125 | local char_data = dofile(snd_config_folder .. char_list) 126 | character_list = char_data.character_list 127 | end 128 | 129 | -- Plugin checker 130 | local required_plugins = { 131 | AutoRetainer = "4.4.4", 132 | TeleporterPlugin = "2.0.2.5", 133 | Lifestream = "2.3.2.8", 134 | SomethingNeedDoing = "1.75", 135 | TextAdvance = "3.2.4.4", 136 | vnavmesh = "0.0.0.54" 137 | } 138 | 139 | if expert_delivery then 140 | required_plugins.Deliveroo = "6.6" 141 | end 142 | 143 | if not CheckPlugins(required_plugins) then 144 | return -- Stops script as plugins not available or versions don't match 145 | end 146 | 147 | -- CBT plugin check for "Enforce Expert Delivery" option 148 | if HasPlugin("Automaton") and (do_rankups or expert_delivery) then 149 | Echo('Ensure you have the "Enforce Expert Delivery" option disabled in CBT plugin.') 150 | end 151 | 152 | if HasPlugin("YesAlready") then 153 | PauseYesAlready() 154 | end 155 | 156 | LogInfo("[KupoBox] ##############################") 157 | LogInfo("[KupoBox] Starting script...") 158 | LogInfo("[KupoBox] snd_config_folder: " .. snd_config_folder) 159 | LogInfo("[KupoBox] char_list: " .. char_list) 160 | LogInfo("[KupoBox] SNDConf+Char: " .. snd_config_folder .. "" .. char_list) 161 | LogInfo("[KupoBox] ##############################") 162 | 163 | -- Deliver GC Items 164 | local function DOL() 165 | local home_world = GetCurrentWorld() == GetHomeWorld() 166 | 167 | -- Return to home for seals from turnins 168 | if not home_world then 169 | Teleporter(FindWorldByID(GetHomeWorld()), "li") 170 | Sleep(1.0) 171 | 172 | repeat 173 | Sleep(0.1) 174 | until not LifestreamIsBusy() and IsPlayerAvailable() 175 | 176 | -- Wait until the player is on the home world 177 | repeat 178 | Sleep(0.1) 179 | home_world = GetCurrentWorld() == GetHomeWorld() 180 | until home_world 181 | end 182 | 183 | -- Wait until the player is fully available 184 | repeat 185 | Sleep(0.1) 186 | until IsPlayerAvailable() 187 | 188 | Teleporter("gc", "li") 189 | 190 | repeat 191 | Sleep(0.1) 192 | until not LifestreamIsBusy() 193 | 194 | if do_rankups then 195 | local rankups_done = false 196 | while not rankups_done do 197 | local can_rankup = CanGCRankUp() 198 | if can_rankup then 199 | DoGcRankUp() 200 | else 201 | rankups_done = true 202 | end 203 | end 204 | end 205 | 206 | OpenGcSupplyWindow(1) 207 | GcProvisioningDeliver() 208 | CloseGcSupplyWindow() 209 | end 210 | 211 | -- Kupo 212 | local function ProcessAltCharacters(character_list, turnins_only) 213 | for i = 1, #character_list do 214 | -- Update alt character name 215 | local alt_char_name = character_list[i] 216 | 217 | -- check if the character is supposed to be skipped 218 | if i <= skip_chars then 219 | LogInfo("[KupoBox] Skipping char " .. i .. ": " .. alt_char_name ) 220 | else 221 | -- Switch characters if required, looks up current character and compares 222 | if GetCharacterName(true) ~= alt_char_name then 223 | RelogCharacter(alt_char_name) 224 | Sleep(7.5) 225 | LoginCheck() 226 | end 227 | 228 | -- Skips trading if turnins_only set to true 229 | if not turnins_only then 230 | Echo("Picking up items from " .. trading_with .. " on server " .. destination_server) 231 | LogInfo("[KupoBox] Picking up items from " .. trading_with .. " on server " .. destination_server) 232 | 233 | Echo("Processing " .. i .. "/" .. #character_list .. ", current character: " .. alt_char_name) 234 | LogInfo("[KupoBox] Processing " .. i .. "/" .. #character_list .. ", current character: " .. alt_char_name) 235 | 236 | -- Check if alt character on correct server 237 | if GetCurrentWorld() == World_ID_List[destination_server].ID then 238 | -- If player is on destination_server then do nothing 239 | LogInfo("[KupoBox] Already on the right server to trade: " .. destination_server) 240 | else 241 | -- If player is not on destination_server then go there 242 | LogInfo("[KupoBox] On the wrong server, transferring to: " .. destination_server) 243 | Teleporter(destination_server, "li") 244 | end 245 | 246 | repeat 247 | Sleep(0.1) 248 | until IsPlayerAvailable() and not LifestreamIsBusy() 249 | 250 | -- Alt character destination type, how alt char is travelling to the main 251 | -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 252 | if destination_type == 0 then 253 | local dest_aetheryte_id = FindZoneIDByAetheryte(destination_aetheryte) 254 | 255 | -- If player is not at the destination then tp there 256 | if GetZoneID() ~= dest_aetheryte_id then 257 | Echo("Teleporting to " .. destination_aetheryte .. " to find " .. trading_with) 258 | LogInfo("[KupoBox] Teleporting to " .. destination_aetheryte .. " to find " .. trading_with) 259 | Teleporter(destination_aetheryte, "tp") 260 | else 261 | Echo("Already in the right zone to meet " .. trading_with) 262 | end 263 | end 264 | 265 | -- Requires main added to friend list for access to estate list teleports 266 | -- Keeping it for future stuff 267 | if destination_type > 0 then 268 | Echo("Teleporting to estate to find " .. trading_with) 269 | LogInfo("[KupoBox] Teleporting to estate to find " .. trading_with) 270 | EstateTeleport(trading_with, destination_house) 271 | end 272 | 273 | -- I really don't like the repeat of destination_type checking here, should probably be refactored into stuff above 274 | -- Handle different destination types 275 | -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 276 | if destination_type == 0 or destination_type == 1 then 277 | -- Waits until main char is present 278 | LogInfo("[KupoBox] Waiting for " .. trading_with) 279 | WaitUntilObjectExists(trading_with) 280 | LogInfo("[KupoBox] Found " .. trading_with) 281 | 282 | -- Paths to main char only if you have do_movement set to true 283 | if do_movement then 284 | -- Path to main char 285 | LogInfo("[KupoBox] do_movement is set to true, moving towards " .. trading_with) 286 | PathToObject(trading_with, 3.0) 287 | else 288 | LogInfo("[KupoBox] do_movement is set to false, not moving") 289 | end 290 | 291 | -- Invite main char to party, needs a target 292 | if party_invite then 293 | PartyInvite(trading_with) 294 | LogInfo("[KupoBox] Inviting " .. trading_with .. " to party") 295 | end 296 | 297 | elseif destination_type == 2 then 298 | -- If destination_type is 2, first go to the estate entrance, then to the main character 299 | PathToObject("Entrance") 300 | Target("Entrance") 301 | Interact() 302 | 303 | repeat 304 | Sleep(0.1) 305 | until IsAddonReady("SelectYesno") 306 | 307 | yield("/callback SelectYesno true 0") 308 | 309 | repeat 310 | Sleep(0.1) 311 | until not IsAddonVisible("SelectYesno") 312 | 313 | -- Waits until main char is present 314 | LogInfo("[KupoBox] Waiting for " .. trading_with) 315 | WaitUntilObjectExists(trading_with) 316 | LogInfo("[KupoBox] Found " .. trading_with) 317 | 318 | -- Paths to main char only if you have do_movement set to true 319 | if do_movement then 320 | -- Path to main char 321 | LogInfo("[KupoBox] do_movement is set to true, moving towards " .. trading_with) 322 | PathToObject(trading_with, 3.0) 323 | else 324 | LogInfo("[KupoBox] do_movement is set to false, not moving") 325 | end 326 | 327 | -- Invite main char to party, needs a target 328 | if party_invite then 329 | PartyInvite(trading_with) 330 | LogInfo("[KupoBox] Inviting " .. trading_with .. " to party") 331 | end 332 | end 333 | 334 | -- Wait for the gil transfer to complete 335 | WaitForGilIncrease(1) 336 | 337 | -- Notify when all characters are finished 338 | if i == #character_list then 339 | Echo("Finished all " .. #character_list .. " characters") 340 | LogInfo("Finished all " .. #character_list .. " characters") 341 | end 342 | 343 | -- Disband party once gil trigger has happened 344 | if party_invite and IsInParty() then 345 | LogInfo("[KupoBox] Disbanding party") 346 | PartyDisband() 347 | Sleep(0.1) 348 | end 349 | end 350 | 351 | -- Deliver GC supply items 352 | DOL() 353 | 354 | -- Deliveroo expert delivery 355 | if expert_delivery and CanExpertDelivery() then 356 | GCDeliverooExpertDelivery() 357 | end 358 | 359 | -- Alt character handling to go home 360 | if return_home then 361 | LogInfo("[KupoBox] Returning home") 362 | ReturnHomeWorld() 363 | 364 | if return_location and return_location ~= "" then 365 | LogInfo(string.format("[KupoBox] Attempting to go to %s", return_location)) 366 | -- Use "li" for lifestream stuff, otherwise use "tp" 367 | local teleport_type = TeleportType(return_location) and "li" or "tp" 368 | Teleporter(return_location, teleport_type) 369 | end 370 | end 371 | end 372 | end 373 | end 374 | 375 | ProcessAltCharacters(character_list, turnins_only) 376 | LogInfo("[KupoBox] All characters complete, script finished") 377 | 378 | if do_ays_multi then 379 | yield("/ays m") 380 | end 381 | 382 | if HasPlugin("YesAlready") then 383 | RestoreYesAlready() 384 | end -------------------------------------------------------------------------------- /Scripts/GC Supply Scripts/README.md: -------------------------------------------------------------------------------- 1 | # GC Supply Scripts 2 | 3 | ![Status](https://img.shields.io/badge/status-working-brightgreen) 4 | 5 | These scripts are for levelling your DoL jobs on an alt account, they require two accounts and are not compatible with a single account. 6 | 7 | However, you can use the `Kupo Box GC Edition` script as a standalone script for turnins (provided you have another method of obtaining the required items) and/or expert delivery. 8 | 9 | They are designed to automatically tell you what GC turnins you need for your DoL jobs by giving you an items to gather list, which are then used to distribute from your main account to your alt account using the provided scripts. 40 characters will take around 2 hours for all scripts to complete, with 2 minutes of manual work buying from the market board. 10 | 11 | ## Known Issues 12 | 13 | - Multiple DoL jobs selected can incorrectly include the items required at max level. 14 | 15 | ## Key Features 16 | 17 | - **Dual-Account Compatibility**: The scripts are designed to work with two accounts, allowing you to level your Disciple of the Land (DoL) jobs on an alt account by distributing items from your main account. 18 | - **Automated Item List Generation**: The scripts automatically generate a list of items needed for Grand Company (GC) turn-ins, which you can gather on your main account and distribute to your alt account. 19 | - **Seamless Item Distribution**: The scripts facilitate the transfer of items from your main account to your alt account using the provided scripts, ensuring a smooth and efficient process. 20 | - **Automatic Turn-In**: Once the items are distributed, each alt character will automatically turn in the provisioning items at their respective Grand Company. 21 | - **Turnins Only**: You can use `Kupo Box GC Edition` as a standalone GC turnin script if you have a surplus of materials or another way to source them, this can be used alongside `expert_delivery` as a way to cycle through all characters and do your expert delivery. 22 | - **Optional Expert Delivery**: If you have the Deliveroo plugin installed and set `expert_delivery` to true, you can further enhance the delivery process. 23 | 24 | ## Requirements 25 | 26 | Ensure you have the following plugins installed and enabled: 27 | 28 | - AutoRetainer : https://love.puni.sh/ment.json 29 | - Dropbox : https://puni.sh/api/repository/kawaii 30 | - Recommended settings in dropbox are 4 frames delay between trades and 1500ms trade open command throttle. (Ctrl + left click to specify exact values). 31 | - You need to enable "Enable auto-accept trades." under the dropbox settings for receiving items. 32 | - Dropbox UI is required to be visible and on the "Item Trade Queue" tab for trading functionality to operate for giving items. 33 | - Lifestream : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 34 | - Something Need Doing (Expanded Edition) : https://puni.sh/api/repository/croizat 35 | - Teleporter : In the default first party dalamud repository 36 | - TextAdvance : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 37 | - vnavmesh : https://puni.sh/api/repository/veyn 38 | 39 | Optional plugins: 40 | - Deliveroo : https://plugins.carvel.li/ 41 | - Only required if expert_delivery is set to true 42 | 43 | ## Installation 44 | 45 | 1. Verify all required plugins are installed and enabled. 46 | 2. Download the latest vac_functions and vac_lists files from [SNDScripts](https://github.com/WigglyMuffin/SNDScripts). 47 | 3. Place the vac_functions and vac_lists files in your SND config folder (`%appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing`) of both accounts. You can place them elsewhere but you will need to adjust the `load_functions_file_location` line of each script to point to the correct path. 48 | 4. Download the latest GC Supply script files (Auto Gen Provisioning List, Trade GC Items and Kupo Box GC Edition) from the [GC Supply Scripts folder](https://github.com/WigglyMuffin/SNDScripts/tree/main/Scripts/GC%20Supply%20Scripts). 49 | 5. Import the scripts into your SND environment (`/snd` and import the scripts). Optionally name the imported scripts in SND to match the file name. 50 | 51 | ## Getting Started 52 | 53 | 1. Configure the `character_list` inside the `vac_char_list.lua` file to include all of your chosen alt account characters following the format specified inside of the file, place this into your `%appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing\` of the user account your alt account is located. 54 | 2. Run `Auto gen Provisioning List.lua` on your alt account to generate a `provisioning_list.lua` file which is used for the later scripts, it will be found with GC related things in `%appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing\VAC\GC\`, this will be your relevant user account %appdata%. 55 | 3. Once this script has finished, another file called `list_to_gather.txt` will be generated located in `%appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing\VAC\GC\`, once again your relevant user account %appdata%. This contains the items you need to gather on your main account, such as purchasing items off the market board. 56 | 4. When you have all the items on the account you are trading from, you need to run `Trade GC Items.lua` in the location the alts are coming to, and run a configured `Kupo Box GC Edition.lua` on the alt account so they come and pick up all the needed items. 57 | 5. Each alt character will turn the provisioning items in automatically at their respective GC after picking them up from the main account 58 | 59 | ## Configuration 60 | 61 | ### vac_char_list Configuration 62 | Make sure you have `vac_char_list.lua` configured in the following format or some of the scripts will not work. 63 | 64 | Note that you can also use the `character_list` inside of `Auto Gen Provisioning List.lua` and `Kupo Box GC Edition.lua` instead of using the external list. 65 | 66 | The following lists are for demonstration purposes only, but serve as a reference point as well. 67 | 68 | ``` 69 | local character_list = { 70 | "First Last@Server", 71 | "First Last@Server" 72 | } 73 | ``` 74 | 75 | Make sure the `Trade GC Items.lua` file has the `SNDAltConfigFolder` near the top is pointing to your alts SND %appdata% config folder in the case that you have your alt running under a different user account. 76 | 77 | ## File and Folder Structure 78 | Make sure you roughly follow this file tree structure for these scripts to work. If you run from a single %appdata% then it would be closer to the alt account file tree. 79 | `list_to_gather.txt` and `provisioning_list.lua` will be automatically generated once you run the scripts. 80 | ```bash 81 | C:\Users\Main Account\AppData\Roaming\XIVLauncher\pluginConfigs\SomethingNeedDoing\ 82 | ├── vac_char_list.lua 83 | ├── vac_functions.lua 84 | └── vac_lists.lua 85 | 86 | C:\Users\Alt Account\AppData\Roaming\XIVLauncher\pluginConfigs\SomethingNeedDoing\ 87 | ├── VAC 88 | │ └── GC 89 | │ ├── list_to_gather.txt 90 | │ └── provisioning_list.lua 91 | ├── vac_char_list.lua 92 | ├── vac_functions.lua 93 | └── vac_lists.lua 94 | ``` 95 | -------------------------------------------------------------------------------- /Scripts/GC Supply Scripts/Trade GC Items.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | _____ _ ____ ____ ___ _ 3 | |_ _| __ __ _ __| | ___ / ___|/ ___| |_ _| |_ ___ _ __ ___ ___ 4 | | || '__/ _` |/ _` |/ _ \ | | _| | | || __/ _ \ '_ ` _ \/ __| 5 | | || | | (_| | (_| | __/ | |_| | |___ | || || __/ | | | | \__ \ 6 | |_||_| \__,_|\__,_|\___| \____|\____| |___|\__\___|_| |_| |_|___/ 7 | 8 | 9 | #################### 10 | ## Version ## 11 | ## 1.0.2 ## 12 | #################### 13 | 14 | -> 1.0.0: Initial release 15 | -> 1.0.1: Duplicate name targetting fix and truncation of @World from provisioning_list character names 16 | -> 1.0.2: Fixed duplicate names when matching player to items they require and removed truncation of @World to facilitate this change 17 | 18 | #################################################### 19 | ## Description ## 20 | #################################################### 21 | 22 | https://github.com/WigglyMuffin/SNDScripts 23 | 24 | This script automatically trade GC items from your main character to your alt characters as they show up 25 | 26 | #################################################### 27 | ## Requirements ## 28 | #################################################### 29 | 30 | -> AutoRetainer : https://love.puni.sh/ment.json 31 | -> Teleporter : In the default first party dalamud repository 32 | -> Lifestream : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 33 | -> TextAdvance : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 34 | -> Something Need Doing (Expanded Edition) : https://puni.sh/api/repository/croizat 35 | -> vnavmesh : https://puni.sh/api/repository/veyn 36 | -> Dropbox : https://puni.sh/api/repository/kawaii 37 | -> Recommended settings in dropbox are 4 frames delay between trades and 1500ms trade open command throttle. (Ctrl + left click to specify exact values). 38 | -> You need to enable "Enable auto-accept trades." under the dropbox settings for receiving items. 39 | -> Dropbox UI is required to be visible and on the "Item Trade Queue" tab for trading functionality to operate for giving items. 40 | 41 | #################################################### 42 | ## Settings ## 43 | ##################################################]] 44 | 45 | -- Set your alt accounts %appdata% config location otherwise this script will not work 46 | -- Replace "ff14lowres" with your alt account username if different 47 | snd_alt_config_folder = "C:\\Users\\ff14lowres\\AppData\\Roaming\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 48 | 49 | --[[################################################ 50 | ## Script Start ## 51 | ##################################################]] 52 | 53 | provisioning_list_name_to_load = "provisioning_list.lua" 54 | 55 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 56 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 57 | LoadFunctions = loadfile(load_functions_file_location)() 58 | LoadFileCheck() 59 | 60 | -- Plugin checker 61 | local required_plugins = { 62 | AutoRetainer = "4.4.4", 63 | TeleporterPlugin = "2.0.2.5", 64 | Lifestream = "2.3.2.8", 65 | SomethingNeedDoing = "1.75", 66 | TextAdvance = "3.2.4.4", 67 | vnavmesh = "0.0.0.54" 68 | } 69 | 70 | if not CheckPlugins(required_plugins) then 71 | return -- Stops script as plugins not available or versions don't match 72 | end 73 | 74 | if HasPlugin("YesAlready") then 75 | PauseYesAlready() 76 | end 77 | 78 | alt_vac_config_folder = snd_alt_config_folder .. "VAC" 79 | dofile(alt_vac_config_folder .. '\\GC\\' .. provisioning_list_name_to_load) 80 | 81 | DropboxClearAll() 82 | local list_length = 0 83 | local chars_processed = 0 84 | 85 | for _ in pairs(provisioning_list) do 86 | list_length = list_length + 1 87 | Sleep(0.1) 88 | end 89 | 90 | for index_name, item in pairs(provisioning_list) do 91 | local party_member = "" 92 | local on_list = false 93 | local min_succeeded = false 94 | local btn_succeeded = false 95 | local fsh_succeeded = false 96 | local item_trades_succeeded = false 97 | local gil_trade_succeeded = false 98 | local min_inv_amount = 0 99 | local btn_inv_amount = 0 100 | local fsh_inv_amount = 0 101 | local gil_inv_amount = 0 102 | local trade_status = DropboxIsBusy() 103 | 104 | function RefreshInv(item_list) 105 | min_inv_amount = GetItemCount(tonumber(item_list["MIN"] and item_list["MIN"]["ID"]) or 0) 106 | btn_inv_amount = GetItemCount(tonumber(item_list["BTN"] and item_list["BTN"]["ID"]) or 0) 107 | fsh_inv_amount = GetItemCount(tonumber(item_list["FSH"] and item_list["FSH"]["ID"]) or 0) 108 | gil_inv_amount = tonumber(GetGil()) or 0 109 | end 110 | 111 | function TradeItems(item_list) 112 | Sleep(0.5) 113 | 114 | if GetPartyMemberName(0) .. "@" .. FindWorldByID(GetPartyMemberWorldId(0)) == party_member then 115 | yield("/target <2>") 116 | yield("/focustarget <2>") 117 | yield("/dropbox") 118 | Sleep(1.0) 119 | end 120 | 121 | Echo("############################") 122 | Echo("Starting trades!") 123 | Echo("############################") 124 | 125 | while not item_trades_succeeded do 126 | RefreshInv(item_list) 127 | 128 | -- Handle MIN item 129 | if item_list["MIN"] and not min_succeeded then 130 | local min_id = tonumber(item_list["MIN"]["ID"]) 131 | local min_qty = tonumber(item_list["MIN"]["QTY"]) 132 | 133 | if min_id and GetItemCount(min_id) ~= 0 then 134 | DropboxSetItemQuantity(min_id, false, min_qty) 135 | else 136 | min_succeeded = true 137 | end 138 | else 139 | min_succeeded = true 140 | end 141 | 142 | Sleep(0.5) 143 | 144 | -- Handle BTN item 145 | if item_list["BTN"] and not btn_succeeded then 146 | local btn_id = tonumber(item_list["BTN"]["ID"]) 147 | local btn_qty = tonumber(item_list["BTN"]["QTY"]) 148 | 149 | if btn_id and GetItemCount(btn_id) ~= 0 then 150 | DropboxSetItemQuantity(btn_id, false, btn_qty) 151 | else 152 | btn_succeeded = true 153 | end 154 | else 155 | btn_succeeded = true 156 | end 157 | 158 | Sleep(0.5) 159 | 160 | -- Handle FSH item 161 | if item_list["FSH"] and not fsh_succeeded then 162 | local fsh_id = tonumber(item_list["FSH"]["ID"]) 163 | local fsh_qty = tonumber(item_list["FSH"]["QTY"]) 164 | 165 | if fsh_id and GetItemCount(fsh_id) ~= 0 then 166 | DropboxSetItemQuantity(fsh_id, false, fsh_qty) 167 | else 168 | fsh_succeeded = true 169 | end 170 | else 171 | fsh_succeeded = true 172 | end 173 | 174 | Sleep(0.1) 175 | DropboxStart() 176 | 177 | -- Wait for the item trade to complete 178 | repeat 179 | trade_status = DropboxIsBusy() 180 | 181 | if trade_status then 182 | LogInfo("[GCID] Currently trading...") 183 | Sleep(0.5) 184 | end 185 | until not trade_status -- Exit loop when item trade is no longer busy 186 | 187 | -- Check if trade succeeded 188 | if item_list["MIN"] and GetItemCount(tonumber(item_list["MIN"]["ID"])) == min_inv_amount and not min_succeeded then 189 | Echo("Trading " .. item_list["MIN"]["Item"] .. " failed, will try again") 190 | else 191 | min_succeeded = true 192 | end 193 | 194 | if item_list["BTN"] and GetItemCount(tonumber(item_list["BTN"]["ID"])) == btn_inv_amount and not btn_succeeded then 195 | Echo("Trading " .. item_list["BTN"]["Item"] .. " failed, will try again") 196 | else 197 | btn_succeeded = true 198 | end 199 | 200 | if item_list["FSH"] and GetItemCount(tonumber(item_list["FSH"]["ID"])) == fsh_inv_amount and not fsh_succeeded then 201 | Echo("Trading " .. item_list["FSH"]["Item"] .. " failed, will try again") 202 | else 203 | fsh_succeeded = true 204 | end 205 | 206 | if min_succeeded and btn_succeeded and fsh_succeeded then 207 | item_trades_succeeded = true 208 | end 209 | 210 | Sleep(0.1) 211 | DropboxClearAll() 212 | end 213 | 214 | while not gil_trade_succeeded do 215 | RefreshInv(item_list) 216 | -- Set gil amount to 1 217 | Sleep(0.1) 218 | DropboxSetItemQuantity(1, false, 1) 219 | 220 | Sleep(0.1) 221 | DropboxStart() 222 | 223 | -- Wait for the gil trade to complete 224 | repeat 225 | trade_status = DropboxIsBusy() 226 | if trade_status then 227 | LogInfo("[GCID] Currently trading...") 228 | Sleep(0.5) 229 | end 230 | until not trade_status -- Exit loop when gil trade is no longer busy 231 | 232 | if GetGil() == (gil_inv_amount - 1) then 233 | gil_trade_succeeded = true 234 | else 235 | LogInfo("[GCID] Trade did not succeed, retrying...") 236 | end 237 | 238 | Sleep(0.1) 239 | DropboxClearAll() 240 | end 241 | 242 | ClearFocusTarget() 243 | 244 | if gil_trade_succeeded and IsInParty() then 245 | PartyLeave() 246 | Sleep(0.1) 247 | end 248 | end 249 | 250 | while not on_list do 251 | Echo("############################") 252 | Echo("Waiting for party invite") 253 | Echo("############################") 254 | 255 | if IsInParty() then 256 | PartyLeave() 257 | Sleep(0.1) 258 | end 259 | 260 | repeat 261 | PartyAccept() 262 | Sleep(0.1) 263 | until IsInParty() 264 | 265 | party_member = GetPartyMemberName(0) .. "@" .. FindWorldByID(GetPartyMemberWorldId(0)) 266 | 267 | for i, item_list in pairs(provisioning_list) do 268 | if party_member == i then 269 | Echo("############################") 270 | Echo("Found " .. party_member .. " in trade list") 271 | Echo("Getting Ready to trade") 272 | Echo("############################") 273 | TradeItems(item_list) 274 | on_list = true 275 | break 276 | end 277 | end 278 | 279 | if not on_list then 280 | Echo("############################") 281 | Echo("Did not find " .. party_member .. " in trade list.") 282 | Echo("Disbanding party and starting again") 283 | Echo("############################") 284 | PartyLeave() 285 | Sleep(1.0) 286 | end 287 | end 288 | 289 | if on_list then 290 | Sleep(0.1) 291 | chars_processed = chars_processed + 1 292 | Echo("############################") 293 | Echo("Done! " .. chars_processed .. "/" .. list_length .. " characters processed") 294 | Echo("############################") 295 | Sleep(7.5) 296 | end 297 | end 298 | 299 | DropboxClearAll() 300 | Echo("############################") 301 | Echo("Script finished") 302 | Echo("############################") 303 | 304 | if HasPlugin("YesAlready") then 305 | RestoreYesAlready() 306 | end -------------------------------------------------------------------------------- /Scripts/Job Unlocker/README.md: -------------------------------------------------------------------------------- 1 | # Job Unlocker 2 | 3 | ![Status](https://img.shields.io/badge/status-broken-red) -------------------------------------------------------------------------------- /Scripts/Overseer/Overseer Launcher.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | ############################################################ 3 | ## Overseer ## 4 | ## Launcher ## 5 | ############################################################ 6 | 7 | #################################################### 8 | ## Description ## 9 | #################################################### 10 | 11 | https://github.com/WigglyMuffin/SNDScripts 12 | 13 | Launcher for the Overseer script, set this to the script that runs on Autoretainer Postprocess 14 | 15 | #################################################### 16 | ## Requirements ## 17 | #################################################### 18 | 19 | --> 20 | --> The ability to set this script to run on Autoretainer Postprocess inside of the snd options 21 | 22 | #################################################### 23 | ## Settings ## 24 | ##################################################]] 25 | 26 | local overseer_script_name = "Overseer" -- This is what you have the script named in snd, preferably left to default 27 | 28 | --[[################################################ 29 | ## Script Start ## 30 | ##################################################]] 31 | 32 | ARFinishCharacterPostProcess() 33 | if not IsMacroRunningOrQueued(overseer_script_name) then 34 | yield("/runmacro " .. overseer_script_name) 35 | end -------------------------------------------------------------------------------- /Scripts/Overseer/README.md: -------------------------------------------------------------------------------- 1 | # Overseer 2 | 3 | ![Status](https://img.shields.io/badge/status-needs_testing-blue) 4 | ![Status](https://img.shields.io/badge/working%3F-probably-aquamarine) 5 | 6 | Overseer is a script designed to improve your Auto Retainer experience. It provides automated backup, management and optimisation features for Auto Retainer, ensuring data integrity and enhancing overall efficiency. 7 | 8 | The default values inside the configuration can be used straight away, though it is recommended to configure and adjust anything to suit your required needs, see [Configuration](#configuration) section for more info. 9 | 10 | There will potentially be bugs and weird things happening, please report any issues you encounter, preferably as an issue in this repo, this should be considered a script in the testing period, while all attempts have been made to ensure things run smoothly, there is no guarantee they will. 11 | 12 | ## Disclaimer 13 | 14 | **IMPORTANT:** Overseer directly modifies the Auto Retainer configuration file. There are periodic backups created aimed to prevent data loss in the event of file corruption. See [Backup](#backup-system) section for more info. 15 | 16 | By using Overseer, you acknowledge and accept the following: 17 | 18 | 1. Overseer's modifications will affect Auto Retainer's behaviour. 19 | 2. You are solely responsible for any issues, data loss, or unintended consequences arising from Overseer's use. 20 | 3. Auto Retainer and its developers are not liable for any problems caused by Overseer's modifications. 21 | 4. It is strongly recommended to manually backup your Auto Retainer configuration before first use of Overseer. 22 | 5. Use Overseer at your own risk. We cannot guarantee it won't conflict with Auto Retainer or other software. 23 | 24 | By using Overseer, you agree to these terms and accept full responsibility for its use and any consequences thereof. 25 | 26 | ## Known Issues 27 | 28 | - FC Actions will sometimes fail to apply when doing gc turnins, doesn't affect any other functionality or crash the script. 29 | 30 | ## Planned Features 31 | 32 | - **Character & Retainer Management**: Streamline data handling for all your characters and retainers. 33 | - **Venture Optimisation**: Dynamically adjust venture types based on retainer levels for maximum efficiency. 34 | - Venture type and plan management 35 | 36 | ## Key Features 37 | 38 | - **Automated Backups**: Safeguard your Auto Retainer configuration with backup rotation (up to 50 backups). 39 | - **Submersible Optimisation**: 40 | - Automatic creation and enabling of submersibles. 41 | - Part swapping for optimal voyaging based on submersible rank and configuration, there are submersible and inventory checks to ensure you have the parts. 42 | - Route handling and plan management. 43 | - Optimal vessel behaviour based on number of unlocked submersibles. 44 | - Incorrect submersible route and build corrections. 45 | - **Retainer Optimisation**: 46 | - Plan management. 47 | - **Retainer Scheduling**: 48 | - Retainer timers to only allow ventures to be run during specific times. 49 | - **FC Management**: 50 | - GC expert delivery turnins with option for enabling Seal Sweetener I or II buffs. 51 | - Ceruleum Tank purchasing and topup management. 52 | - Venture purchasing and topup management. 53 | - **Silent Operation**: Works seamlessly in the background with no interruptions. 54 | - **Shutdown Timers**: Option to shutdown your client after a specified time for auth token renewal. 55 | - **Menu Bailouts**: Additional menu bailouts for when a menu gets stuck. 56 | 57 | ## Requirements 58 | 59 | Ensure you have the following plugins installed and enabled: 60 | 61 | - AutoRetainer 62 | - Deliveroo 63 | - Lifestream 64 | - Simple Tweaks 65 | - Something Need Doing (Expanded Edition) 66 | - Teleporter 67 | - TextAdvance 68 | - vnavmesh 69 | 70 | ## Installation 71 | 72 | 1. Verify all required plugins are installed and enabled. 73 | 2. Download the latest `vac_function.lua` and `vac_list.lua` files from [SNDScripts](https://github.com/WigglyMuffin/SNDScripts). 74 | 3. Place the `vac_function.lua` and `vac_list.lua` files in your SND config folder (`%appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing`). You can place them elsewhere but you will need to adjust the `load_functions_file_location` line of Overseer to point to the correct path. 75 | 4. Download the latest Overseer script files (both Overseer and Overseer Launcher) from the [Overseer folder](https://github.com/WigglyMuffin/SNDScripts/tree/main/Scripts/Overseer). 76 | 5. Edit Overseer to configure the settings, this can be in an editor of your choice or inside the SND environment, and use the import button to import the script. 77 | 6. Import Overseer and Overseer Launcher into your SND environment (`/snd` and import the scripts using the `Import macro from clipboard` button). Make sure you name the imported scripts in SND to match the file name, and ensure the scripts are listed as `Lua`. 78 | 7. Optionally though recommended to set Overseer Launcher as the script to run on AutoRetainer CharacterPostProcess, located in SND settings (the `?` icon towards the top middle section of the UI). 79 | 8. Make sure you have "Wait on login screen" enabled in your Auto Retainer settings. 80 | 81 | ## Getting Started 82 | 83 | 1. If this is your first time using Overseer (including first time with a different user account/environment), you need to use `/ays` to open AutoRetainer, go onto the `Statistics` tab and click between the three `Ventures`, `Gil` and `FC Data` tabs, closing AutoRetainer and repeating this a second time, this is to load your character and FC data correctly. 84 | 2. Configure the settings in Overseer (see Configuration section) to match your preferences if you have not done so already. 85 | 3. Start the `Overseer Launcher` script, this will load and start Overseer. 86 | 4. Let Overseer optimise your Auto Retainer experience automatically upon AutoRetainer starting. 87 | 88 | ## Configuration 89 | 90 | Fine-tune Overseer's behaviour by adjusting these parameters in the script's configuration section: 91 | 92 | | Setting | Description | Values Accepted | Default Value | 93 | |---------|-------------|-----------------|---------------| 94 | | `disable_gc_delivery` | Disables attempting any kind of gc delivery on falling under either venture or inventory slot limits | `true` or `false` | `false` | 95 | | `venture_limit` | Minimum value of ventures to trigger buying more ventures, requires Deliveroo to be correctly configured by doing GC deliveries | A number between `1` and `9999` | `100` | 96 | | `inventory_slot_limit` | Amount of inventory slots remaining before attempting a GC delivery to free up slots | A number between `1` and `140` | `30` | 97 | | `buy_ceruleum` | Will attempt to buy ceruleum fuel based on the settings below, if set to false the characters will never attempt to refuel (buy ceruleum fuel off players) | `true` or `false` | `false` | 98 | | `ceruleum_limit` | Minimum value of ceruleum fuel to trigger buying ceruleum fuel | A number between `1` and `139860` | `1000` | 99 | | `ceruleum_buy_amount` | Amount of ceruleum fuel to be purchased when ceruleum_limit is triggered | A number between `1` and `139860` | `99999` | 100 | | `fc_credits_to_keep` | How many credits to always keep, this limit will be ignored when buying FC buffs for GC deliveries | A number between `1` and `999999999` | `13000` | 101 | | `use_fc_buff` | Will attempt to buy and use the seal sweetener buff when doing GC deliveries | `true` or `false` | `false` | 102 | | `force_return_subs_that_need_swap` | Will force return submarines to swap parts even if they're already sent out, if set to false it will wait until they're back | `true` or `false` | `false` | 103 | 104 | You can also customise submersible builds and retainer venture types in their respective sections. 105 | 106 | ### Timers Configuration 107 | 108 | These settings allow the script to automatically shut down the game after X minutes, good if you want to reset the token every day and have something else start the game again 109 | | Setting | Description | Values Accepted | Default Value | 110 | |---------|-------------|-----------------|---------------| 111 | | `enable_auto_shutdown` | Enables the auto shutdown feature | `true` or `false` | `false` | 112 | | `shutdown_timer` | How many minutes the script will wait before shutting the client down in minutes, as an example 1440 minutes is a day | A number between `1` and `4320` | `1440` | 113 | 114 | If you want to set your retainers to only run between x and x hours of the day you can use these settings to set a schedule of active retainer hours. 115 | This uses your local PC time and in a 24 hour format, therefore adjust the hours and minutes to your requirements. 116 | | Setting | Description | Values Accepted | Default Value | 117 | |---------|-------------|-----------------|---------------| 118 | | `enable_retainer_schedule` | Enables the retainer schedule and to be used with `retainer_active_hours` | `true` or `false` | `false` | 119 | 120 | The script includes a configuration table for retainer active hours. Here's an example of how to configure them: 121 | 122 | ```lua 123 | local retainer_active_hours = { 124 | start_time = { hour = 17, minute = 00 }, -- 5:00 PM 125 | end_time = { hour = 2, minute = 05 } -- 2:05 AM 126 | } 127 | ``` 128 | 129 | ### Submersible Configuration 130 | 131 | The script includes a configuration table for submersible builds. Here's an explanation of the configuration structure: 132 | 133 | ```lua 134 | local submersible_build_config = { 135 | { min_rank = 1, max_rank = 14, build = "SSSS", plan_type = 3, unlock_plan = "31d90475-c6a1-4174-9f66-5ec2e1d01074", point_plan = "6e38ab7a-05c2-40b7-84a1-06f087704371" }, 136 | { min_rank = 15, max_rank = 89, build = "SSUS", plan_type = 3, unlock_plan = "31d90475-c6a1-4174-9f66-5ec2e1d01074", point_plan = "6e38ab7a-05c2-40b7-84a1-06f087704371" }, 137 | { min_rank = 90, max_rank = 120, build = "SSUC", plan_type = 4, unlock_plan = "31d90475-c6a1-4174-9f66-5ec2e1d01074", point_plan = "6e38ab7a-05c2-40b7-84a1-06f087704371" }, 138 | } 139 | ``` 140 | 141 | Each entry in the table represents a configuration for a specific rank range and contains: 142 | 143 | - `min_rank`: Minimum rank value (inclusive) 144 | - `max_rank`: Maximum rank value (inclusive) 145 | - `build`: String representing the parts the submersibles should use 146 | - `plan_type`: Vessel behavior (0 = Unlock, 1 = Redeploy, 2 = LevelUp, 3 = Unlock, 4 = Use plan) 147 | - `unlock_plan`: GUID corresponding to the unlock plan, this plan uses `plan_type = 3` 148 | - `point_plan`: GUID corresponding to the point plan, this plan uses `plan_type = 4` 149 | 150 | Keep in mind that `plan_type` determines which plan is used, for values 0-2 no plan is used and is managed by AutoRetainer, value 3 uses `unlock_plan` and value 4 uses `point_plan` for each submersible. Therefore, if you are levelling a submersible using a plan, you would use `plan_type = 3` with an appropriate `unlock_plan` set, if you are farming you would use `plan_type = 4` with an appropriate `point_plan` set instead. 151 | 152 | ### Unlock Plans Configuration 153 | 154 | Unlock plans are defined in the "Open Voyage Unlockable Planner" of AutoRetainer. Here's an example of how to configure them: 155 | 156 | ```lua 157 | local unlock_plans = { 158 | { 159 | GUID = "579ba94d-4b73-4afe-9be1-999225e24af2", 160 | Name = "Overseer OJ Unlocker", 161 | ExcludedRoutes = { 101,100,99,98,97,96,95,93,92,91,90,89,88,80,81,82,83,84,86,85,87,79,78,77,76,75,74,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,29,24,23,22,21,18,17,16,13,12,11,9,8,7,6,4,3,102,103,104,105,48,36,51,50,46,45,44,41,40,35,53 }, 162 | UnlockSubs = true 163 | }, 164 | { 165 | GUID = "31d90475-c6a1-4174-9f66-5ec2e1d01074", 166 | Name = "Overseer Optimal Unlocker", 167 | ExcludedRoutes = { 3,6,13,22,23,24,29,36,40,41,45,44,46,48,50,51,54,56,58,60,63,64,66,67,68,69,71,80,86,90,92,103,105,107,109,110,112 }, 168 | UnlockSubs = true 169 | }, 170 | -- Add more unlock plans here as needed 171 | } 172 | ``` 173 | 174 | ### Point Plans Configuration 175 | 176 | Point plans are defined in the "Open Voyage Route Planner" of AutoRetainer. Here's an example of how to configure them: 177 | 178 | ```lua 179 | local point_plans = { 180 | { 181 | GUID = "6e38ab7a-05c2-40b7-84a1-06f087704371", 182 | Name = "Overseer OJ", 183 | Points = {15,10} 184 | }, 185 | { 186 | GUID = "04fbb61c-5800-40e6-8c67-2467796bf80e", 187 | Name = "Overseer JORZ", 188 | Points = { 10,15,18,26 } 189 | }, 190 | { 191 | GUID = "644317d3-34e1-44f3-a950-5fa5bdc8de04", 192 | Name = "Overseer MROJZ", 193 | Points = { 13,18,15,10,26 } 194 | }, 195 | -- Add more point plans here as needed 196 | } 197 | ``` 198 | 199 | Note: You cannot directly copy-paste these configurations. You'll need to manually copy each section to meet the required format. 200 | 201 | ## Submersible Behaviour 202 | 203 | For levelling, all submersibles will follow the `unlock_plan` defined in the configuration, with the following vessel behaviour: 204 | - The first submersible will use "Unlock + Spam one destination" until all four submersibles are unlocked, then switch to "Unlock + Pick max amount of destinations". 205 | - The second, third, and fourth submersibles will use "Unlock + Pick max amount of destinations". 206 | - Once each individual submersible reaches the configured rank value for farming, they will automatically switch to the `point_plan` you have set, while the remaining submersibles continue to level. 207 | 208 | If you already have submersibles and are not starting out, it is advised that you remain on your current `unlock_plan`, otherwise your submersibles will attempt to unlock previous zones and this will slow down your progress, if you used the pinned OJ Unlocker then you only need to swap to that, otherwise if you use a custom plan you will have to manually add it to the `Unlock Plans Configuration` section inside Overseer. 209 | 210 | ## Backup System 211 | 212 | Overseer implements a robust backup system for your Auto Retainer configuration: 213 | 214 | - Creates backups automatically 215 | - Maintains a rolling set of up to 50 recent backups 216 | - Ensures you can always revert to a previous stable configuration 217 | 218 | ## Changelog 219 | 220 | - **1.6.3**: Added a check to ensure AutoRetainer is always enabled at the start of the script 221 | - **1.6.2**: Added functionality to refresh AutoRetainer data for submersibles 222 | - **1.6.1**: Improved validation and logging for optimal build configuration retrieval 223 | - **1.6.0**: Better save functionality and added delays to ensure data consistency during post AR tasks 224 | - **1.5.9**: Added rank validation and improved logging in GetOptimalBuildForRank function 225 | - **1.5.8**: Added pause and restore for YesAlready plugin after player login and logout 226 | - **1.5.7**: Fixed movement when inside a house and added compatibility with Title Edit plugin 227 | - **1.5.6**: Increased distance thresholds for additional entrance interaction 228 | - **1.5.5**: Reverted distance thresholds for "Voyage Control Panel" and "Summoning Bell" interactions 229 | - **1.5.4**: Updated distance thresholds for object interactions and fixed logging for submersible enabling 230 | - **1.5.3**: Fixed inefficiencies for use_fc_buff option to not teleport more than needed 231 | - **1.5.2**: 232 | - **New feature**: Automatically disables title screen if simple tweaks is installed. 233 | - **New feature**: Now automatically changes an AR setting so it waits on the main menu between retainers/submersibles. 234 | - **Bug fix**: Fixed a potential crash when checking if a character should buy ceruleum 235 | - **Improvement**: Switched from using a collection to disable AR to using `/xlenableplugin` and `/xldisableplugin` instead. 236 | - **WIP**: Started initial work on proper retainer support and added configurations that are not functional yet. 237 | - **1.5.1**: Added a setting which allows you to set retainer active hours, so you can run retainers for only X hours a day if preferred. Also some potential improvements to stuck detection with minor code cleanup 238 | - **1.5.0**: Rewrote a couple functions to make overseer work with the updated AutoRetainer config layout 239 | - **1.4.7**: Fixed an issue where it would crash if character had no plot 240 | - **1.4.6**: Added requested logic changes 241 | - **1.4.5**: Some improvements and some fixes. Overseer will now wait 60 seconds after creating a new submersible to mitigate an issue it has with AR. 242 | - **1.4.4**: Adjusted some code which was causing overseer to get stuck for too long when dealing with new submersibles 243 | - **1.4.3**: Fixed an issue which has probably caused overseer to be inconsistent for months now, relating to how it calculates when to do part swaps. Also fixed or optimized many other smaller things. Likely the most stable release yet. 244 | - **1.4.2**: Fixed another bug which could cause overseer to get stuck at the voyage panel 245 | - **1.4.1**: Made a minor adjustment to potentially fix an issue where it causes AR to get stuck on the main menu for some 246 | - **1.4.0**: Added a shutdown timer and made further consistency improvements, should now unstuck in locations where it had a chance to get stuck before. The script now also enables submersibles in enabled fcs that for some reason are disabled, which should also fix when the script fails to enable the submersible right after creation. 247 | - **1.3.9**: Further improved the automatic fixing of submersibles 248 | - **1.3.8**: Fixed a minor mistake causing 1.3.7 to not run for some 249 | - **1.3.7**: Overseer should now automatically fix submersibles that have not been sent out after a part swap 250 | - **1.3.6**: Further consistency improvements 251 | - **1.3.5**: More attempts at fixing inconsistencies 252 | - **1.3.4**: Potential fix to submersibles not being sent out after creation 253 | - **1.3.3**: Fixed a bug caused by the previous update causing it to not part swap at all 254 | - **1.3.2**: A lot of bugfixes 255 | - **1.3.1**: More fixes related to plan assignment and inconsistent finalizing 256 | - **1.3.0**: Added another check to try to remedy inconsistencies in part swapping. 257 | - **1.2.9**: Attempted to further fix inconsistencies with part swapping. Also added a character exclusion list so you can exclude certain characters from submersible processing 258 | - **1.2.8**: Various optimizations and fixed a couple more bugs related to part swapping and submersible vessel behavior 259 | - **1.2.7**: Fixed an issue causing data not to be saved/read properly so the script took the wrong actions 260 | - **1.2.6**: Reverted some optimization due to bugs 261 | - **1.2.5**: Optimized some areas of the script and fixed a bug causing it to rarely fail when accessing the AR config file 262 | - **1.2.4**: Submersible parts should now properly retry if they somehow failed to swap correctly 263 | - **1.2.3**: Fixed the script rarely getting stuck 264 | - **1.2.2**: Even more consistency improvements 265 | - **1.2.1**: Consistency improvements 266 | - **1.2.0**: Fixed a bug causing finalized subs to sometimes not be sent out. 267 | - **1.1.9**: Reworked parts of the script to further address inconsistencies. 268 | - **1.1.8**: Fixed an issue where characters without retainers did not swap parts properly. 269 | - **1.1.7**: Properly resolved the previous issue. 270 | - **1.1.6**: Fixed a bug where multi-tasking wouldn't reenable after completing all tasks. 271 | - **1.1.5**: Ensured multi-tasking is disabled correctly during retainer/submersible processing to prevent premature logout. 272 | - **1.1.4**: Additional fixes for submersible part swapping. 273 | - **1.1.3**: Fixed a bug preventing parts from being swapped correctly. 274 | - **1.1.2**: Potential fix for minor bugs related to submersible part swapping. 275 | - **1.1.1**: Fixed a logic issue causing submarines set to finalize to stay finalized. 276 | - **1.1.0**: Resolved a logic issue where parts wouldn’t swap even when they should. 277 | - **1.0.9**: Fixed a logic issue where the script misinterpreted available parts. 278 | - **1.0.8**: Changed default behavior to keep submarines on voyages during part swaps; added a toggle (default: off). 279 | - **1.0.7**: Fixed a bug causing the AR file to save incompletely. 280 | - **1.0.6**: Added support for retainer bells inside houses, not just workshops. 281 | - **1.0.5**: Improved part swap logic to ensure required parts are available; fixed loading issues with the entrust list. 282 | - **1.0.4**: Added better error handling and fixed a typo. 283 | - **1.0.3**: Simplified folder swapping further. 284 | - **1.0.2**: Made it easier to swap paths for multiple accounts using the same Windows user; moved backups and character data to the AutoRetainer directory. 285 | - **1.0.1**: Enhanced backup functionality and adjusted settings for consistency. 286 | - **1.0.0**: Initial release. 287 | -------------------------------------------------------------------------------- /Scripts/Questionable Companion/README.md: -------------------------------------------------------------------------------- 1 | # Questionable Companion 2 | 3 | ![Status](https://img.shields.io/badge/status-working-brightgreen) 4 | ![Status](https://img.shields.io/badge/bugs%3F-maybe-yellow) 5 | 6 | ## This script is mostly working. 7 | 8 | ### Make sure you have `vac_functions.lua`, `vac_lists.lua` in your snd config folder. 9 | These can be found in the top directory of this repo. 10 | 11 | Place them in your Something Need Doing config directory, which will be located at `%appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing\` 12 | -------------------------------------------------------------------------------- /Scripts/Retainer Maker/README.md: -------------------------------------------------------------------------------- 1 | # Retainer Maker 2 | 3 | ![Status](https://img.shields.io/badge/status-needs_testing-blue) 4 | 5 | ### Make sure you have `vac_functions.lua`, `vac_lists.lua` in your snd config folder. 6 | These can be found in the top directory of this repo. 7 | 8 | Place them in your Something Need Doing config directory, which will be located at `%appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing\` 9 | -------------------------------------------------------------------------------- /Scripts/Retainer Maker/Retainer Maker CharListGen.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | ############################################################ 3 | ## Retainer Maker ## 4 | ## Character List Generator ## 5 | ############################################################ 6 | 7 | 8 | #################### 9 | ## Version ## 10 | ## 1.0.0 ## 11 | #################### 12 | 13 | -> 1.0.0: Initial release 14 | 15 | #################################################### 16 | ## Description ## 17 | #################################################### 18 | 19 | Generates a character list you can insert into the retainer maker script 20 | 21 | if outputs the list into %appdata%\XIVLauncher\pluginConfigs\SomethingNeedDoing\VAC\Tools 22 | aka the snd config folder for that installation 23 | 24 | #################################################### 25 | ## Required Plugins ## 26 | #################################################### 27 | 28 | -> None 29 | 30 | ##################### 31 | ## Settings ## 32 | ###################]] 33 | 34 | local gen_char_list = { 35 | "Mrow Mrow@Louisoux", 36 | "Smol Meow@Lich", 37 | "Beeg Meow@Zodiark", 38 | } 39 | 40 | -- can leave this empty 41 | local retainer_jobs_to_include_on_all = { 42 | {"MIN", 1}, 43 | {"BTN", 1} 44 | } 45 | 46 | 47 | --[[################################# 48 | # DON'T TOUCH ANYTHING BELOW HERE # 49 | # UNLESS YOU KNOW WHAT YOU'RE DOING # 50 | ##################################### 51 | 52 | ################### 53 | # FUNCTION LOADER # 54 | #################]] 55 | 56 | 57 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 58 | vac_config_folder = snd_config_folder .. "\\VAC\\" 59 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 60 | LoadFunctions = loadfile(load_functions_file_location) 61 | LoadFunctions() 62 | LoadFileCheck() 63 | 64 | --[[########### 65 | # MAIN SCRIPT # 66 | #############]] 67 | 68 | local tools_folder = vac_config_folder .. "Tools\\" 69 | EnsureFolderExists(vac_config_folder) 70 | EnsureFolderExists(tools_folder) 71 | 72 | -- Open file for writing in the tools folder 73 | local file = io.open(tools_folder .. "Make Retainers Chars.lua", "w") 74 | 75 | -- Create the desired output structure 76 | local function generate_character_list() 77 | file:write("local chars = {\n") 78 | for _, char_str in ipairs(gen_char_list) do 79 | file:write("{\n") 80 | file:write(" [\"Character Name\"] = \"" .. char_str .. "\",\n") 81 | file:write(" [\"Retainers\"] = {\n") 82 | for _, retainer in ipairs(retainer_jobs_to_include_on_all) do 83 | file:write(" {\"" .. retainer[1] .. "\", " .. retainer[2] .. "},\n") 84 | end 85 | file:write(" }\n") 86 | file:write("},\n") 87 | end 88 | file:write("}") 89 | end 90 | 91 | -- Write the formatted list to the file 92 | generate_character_list() 93 | 94 | -- Close the file 95 | file:close() -------------------------------------------------------------------------------- /Scripts/Retainer Maker/Retainer Maker.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | ############################################################ 3 | ## RETAINER ## 4 | ## MAKER ## 5 | ############################################################ 6 | 7 | 8 | #################### 9 | ## Version ## 10 | ## 1.0.0 ## 11 | #################### 12 | 13 | -> 1.0.0: Initial release 14 | 15 | #################################################### 16 | ## Description ## 17 | #################################################### 18 | 19 | https://github.com/WigglyMuffin/SNDScripts 20 | 21 | This script rotates between provided characters and creates retainers for them using set settings, also buys and equips their needed weapon/tool. Worth noting it makes all retainers in limsa 22 | Optionally also does the venture quest afterwards, or if you want you can use this script to finish venture quests on characters with retainers already 23 | 24 | #################################################### 25 | ## Requirements ## 26 | #################################################### 27 | 28 | -> Teleporter : In the default first party dalamud repository 29 | -> Pandora - https://love.puni.sh/ment.json 30 | -> Something Need Doing (Expanded Edition) - https://puni.sh/api/repository/croizat 31 | -> Textadvance - https://raw.githubusercontent.com/NightmareXIV/MyDalamudPlugins/main/pluginmaster.json 32 | -> Vnavmesh - https://puni.sh/api/repository/veyn 33 | -> AutoRetainer : https://love.puni.sh/ment.json 34 | 35 | These are only optional if you do not need to do the venture quest: 36 | -> Rotation Solver Reborn - https://raw.githubusercontent.com/FFXIV-CombatReborn/CombatRebornRepo/main/pluginmaster.json 37 | -> Questionable - https://plugins.carvel.li/ 38 | 39 | #################################################### 40 | ## Settings ## 41 | ##################################################]] 42 | 43 | -- Keep this on unless you intend on using the script to only finish the venture quests 44 | MAKE_RETAINERS = true 45 | 46 | -- Do the venture quest 47 | DO_VENTURE_QUEST = true 48 | 49 | -- This is where you place your character list with configured retainers, you can generate a list you can edit/use using the list generator provided in the same folder, or you can type it all out manually. 50 | -- It supports any job that a retainer can take, abbreviated. 51 | local chars = { 52 | { 53 | ["Character Name"] = "First Last@Server", 54 | ["Retainers"] = { 55 | {"MIN", 1}, 56 | {"BTN", 1} 57 | } 58 | }, 59 | { 60 | ["Character Name"] = "Last First@Server", 61 | ["Retainers"] = { 62 | {"ARC", 1}, 63 | {"MRD", 1} 64 | } 65 | }, 66 | } 67 | 68 | 69 | --[[################################################ 70 | ## Script Start ## 71 | ##################################################]] 72 | 73 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 74 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 75 | LoadFunctions = loadfile(load_functions_file_location)() 76 | LoadFileCheck() 77 | 78 | -- Plugin checker 79 | local required_plugins = { 80 | AutoRetainer = "4.4.4", 81 | PandorasBox = "1.6.2.5", 82 | SomethingNeedDoing = "1.75", 83 | TeleporterPlugin = "2.0.2.5", 84 | TextAdvance = "3.2.4.4", 85 | vnavmesh = "0.0.0.54" 86 | } 87 | 88 | if not CheckPlugins(required_plugins) then 89 | return -- Stops script as plugins not available or versions don't match 90 | end 91 | 92 | if HasPlugin("YesAlready") then 93 | PauseYesAlready() 94 | end 95 | 96 | -- Lists of valid retainer jobs and the location of the item they need to buy in the shop 97 | local valid_jobs = { 98 | GLA = { class = "DoW", store_location = 1, itemID = 1601, retainer_job_positon = 0}, -- Weathered Shortsword 99 | PGL = { class = "DoW", store_location = 10, itemID = 1680, retainer_job_positon = 3}, -- Weathered Hora 100 | MRD = { class = "DoW", store_location = 4, itemID = 1749, retainer_job_positon = 1}, -- Weathered War Axe 101 | LNC = { class = "DoW", store_location = 7, itemID = 1819, retainer_job_positon = 4}, -- Weathered Spear 102 | ROG = { class = "DoW", store_location = 13, itemID = 7952, retainer_job_positon = 5}, -- Weathered Daggers 103 | ARC = { class = "DoW", store_location = 16, itemID = 1889, retainer_job_positon = 6}, -- Weathered Shortbow 104 | CNJ = { class = "DoM", store_location = 11, itemID = 1995, retainer_job_positon = 2}, -- Weathered Cane 105 | THM = { class = "DoM", store_location = 1, itemID = 2055, retainer_job_positon = 7}, -- Weathered Scepter 106 | ACN = { class = "DoM", store_location = 6, itemID = 2142, retainer_job_positon = 8}, -- Weathered Grimoire 107 | MIN = { class = "DoL", store_location = 1, itemID = 2519, retainer_job_positon = 9}, -- Weathered Pickaxe 108 | BTN = { class = "DoL", store_location = 3, itemID = 2545, retainer_job_positon = 10}, -- Weathered Hatchet 109 | FSH = { class = "DoL", store_location = 5, itemID = 2571, retainer_job_positon = 11}, -- Weathered Fishing Rod 110 | } 111 | 112 | -- Function used to find details about the job in the valid_jobs list 113 | local function GetJobDetails(job_to_find) 114 | local details = valid_jobs[job_to_find] 115 | if details then 116 | return details 117 | else 118 | return nil, nil, nil -- Return nils if the job is not found 119 | end 120 | end 121 | 122 | function BuyRetainerJobItem(job, item_amount) 123 | local job_details = GetJobDetails(job) 124 | 125 | if not job_details then 126 | Echo("Job is not in any list?") 127 | return 128 | end 129 | -- Move to and target the right vendor for the class you're getting items for 130 | if job_details.class == "DoW" or job_details.class == "DoM" then 131 | Movement(-236.34, 16.20, 40.77, 0.5) 132 | Target("Faezghim") 133 | else -- since it's not the two others the only option left is DoL 134 | Movement(-245.87, 16.20, 40.59, 0.5) 135 | Target("Syneyhil") 136 | end 137 | Sleep(0.5) 138 | Interact() 139 | repeat 140 | Sleep(0.1) 141 | until IsAddonReady("SelectIconString") 142 | if job_details.class == "DoW" then -- Only need to check for DoW since if it's not that it's always DoM or DoL 143 | yield("/pcall SelectIconString true 0") 144 | else 145 | yield("/pcall SelectIconString true 1") 146 | end 147 | repeat 148 | Sleep(0.1) 149 | until IsAddonReady("SelectString") 150 | yield("/pcall SelectString true 0") 151 | repeat 152 | Sleep(0.1) 153 | until IsAddonReady("Shop") 154 | for i = 1, item_amount do 155 | BuyFromStoreSingle(job_details.store_location) 156 | end 157 | yield("/pcall Shop true -1") 158 | repeat 159 | Sleep(0.1) 160 | until not IsAddonVisible("Shop") 161 | repeat 162 | Sleep(0.1) 163 | until IsAddonVisible("SelectString") 164 | yield("/pcall SelectString true 5") 165 | repeat 166 | Sleep(0.1) 167 | until IsPlayerAvailable() 168 | end 169 | 170 | function CreateRetainerName() 171 | math.randomseed(os.time() + os.clock() * 100000) 172 | 173 | -- Prefixes 174 | local prefixes = { 175 | "Ari", "Ela", "Luna", "Mira", "Ser", "Tala", "Cala", "Vira", "Zara", "Rina", 176 | "Fae", "Syl", "Ilia", "Alia", "Bela", "Cora", "Del", "Eli", "Fira", "Lyra", 177 | "Isla", "Nora", "Eira", "Thal", "Vala", "Yara", "Sora", "Rhea", "Iona", 178 | "Ama", "Nyla", "Syla", "Oria", "Shira", "Asha", "Juna", "Mellia", "Fina" 179 | } 180 | 181 | -- Syllables 182 | local middle_syllables = { 183 | "la", "ra", "bel", "wen", "rin", "th", "ni", "sol", "dra", "nor", "el", 184 | "ara", "lyn", "mir", "ven", "ial", "sil", "dar", "ria", "sha", "thys", 185 | "sen", "wyn", "isa", "lys", "iel", "ira", "wen", "reth", "vel", "zia" 186 | } 187 | 188 | -- Suffixes 189 | local suffixes = { 190 | "na", "lia", "ra", "elle", "wyn", "a", "ine", "ara", "essa", "ina", "ora", 191 | "ira", "ria", "tha", "yn", "aya", "era", "sia", "ia", "cia", "issa", "rielle", 192 | "vina", "ona", "lina", "lora", "elle", "itha", "dora", "etta", "sha" 193 | } 194 | 195 | local function EndsWithVowel(s) 196 | return s:match("[aeiouAEIOU]$") 197 | end 198 | 199 | -- Check if a string starts with a vowel 200 | local function StartsWithVowel(s) 201 | return s:match("^[aeiouAEIOU]") 202 | end 203 | 204 | -- Check for forbidden character combinations in the name 205 | local function HasForbiddenCombo(name) 206 | local forbidden_combinations = { "kk", "zz", "xx", "yy", "thk" } 207 | for _, combo in ipairs(forbidden_combinations) do 208 | if name:find(combo) then 209 | return true 210 | end 211 | --Sleep(0.0001) 212 | end 213 | return false 214 | end 215 | 216 | -- Function to ensure natural flow 217 | local function IsValidSyllableTransition(last_part, next_part) 218 | if EndsWithVowel(last_part) and StartsWithVowel(next_part) then 219 | return false 220 | end 221 | return true 222 | end 223 | 224 | -- Function to create a random female fantasy name 225 | local function CreateRetainerName(max_length) 226 | local name = "" 227 | local attempts = 0 228 | 229 | repeat 230 | -- Decide on how long the name should be (2 to 4 syllables) 231 | local syllableCount = math.random(2, 4) 232 | 233 | -- Start with a random prefix 234 | local prefix = prefixes[math.random(#prefixes)] 235 | name = prefix 236 | 237 | -- Add middle syllables based on the length decision 238 | for i = 1, syllableCount - 1 do 239 | local middle = middle_syllables[math.random(#middle_syllables)] 240 | if IsValidSyllableTransition(name, middle) and #name + #middle < max_length - 3 then 241 | name = name .. middle 242 | end 243 | --Sleep(0.0001) 244 | end 245 | 246 | -- Add a random suffix 247 | local suffix = suffixes[math.random(#suffixes)] 248 | if IsValidSyllableTransition(name, suffix) and #name + #suffix < max_length then 249 | name = name .. suffix 250 | end 251 | 252 | attempts = attempts + 1 253 | until not HasForbiddenCombo(name) or attempts > 10 -- Retry if forbidden combo found 254 | 255 | -- Capitalize the first letter 256 | name = name:gsub("^%l", string.upper) 257 | return name 258 | end 259 | 260 | local retainerName = CreateRetainerName(19) 261 | return retainerName 262 | end 263 | 264 | function CreateRetainer() 265 | Target("Frydwyb") 266 | Interact() 267 | repeat 268 | Sleep(0.1) 269 | until IsAddonReady("SelectString") 270 | yield("/pcall SelectString true 0") 271 | repeat 272 | Sleep(0.1) 273 | until IsAddonReady("SelectYesno") or IsPlayerAvailable() 274 | if IsPlayerAvailable() then 275 | Echo("No more retainers can be made") 276 | return 277 | end 278 | yield("/pcall SelectYesno true 0") 279 | repeat 280 | Sleep(0.1) 281 | until IsAddonReady("_CharaMakeTitle") 282 | Sleep(1) -- just extra safety 283 | 284 | -- Create and randomize the miqo 285 | yield("/pcall _CharaMakeProgress true 0 13 0 Miqo'te 2") 286 | yield("/pcall _CharaMakeProgress true -13 -1") 287 | yield("/pcall _CharaMakeProgress true 0 13 0 Miqo'te 0") 288 | Sleep(0.5) 289 | yield("/pcall _CharaMakeFeature true -9 0") 290 | Sleep(0.5) 291 | yield("/pcall _CharaMakeFeature false 100") 292 | repeat 293 | Sleep(0.1) 294 | until IsAddonReady("SelectYesno") 295 | yield("/pcall SelectYesno true 1") 296 | repeat 297 | Sleep(0.1) 298 | until not IsAddonVisible("SelectYesno") 299 | repeat 300 | Sleep(0.1) 301 | until IsAddonReady("SelectYesno") 302 | yield("/pcall SelectYesno true 0") 303 | repeat 304 | Sleep(0.1) 305 | until IsAddonReady("SelectString") 306 | -- give it a carefree attitude 307 | yield("/pcall SelectString true 3") 308 | repeat 309 | Sleep(0.1) 310 | until IsAddonReady("SelectYesno") 311 | yield("/pcall SelectYesno true 0") 312 | repeat 313 | Sleep(0.1) 314 | until IsAddonReady("InputString") 315 | 316 | -- Name the miqo 317 | local retainer_named = false 318 | while not retainer_named do 319 | local retainer_name = CreateRetainerName() 320 | Echo("Attempting to name retainer " .. retainer_name) 321 | yield("/pcall InputString true 0 "..retainer_name.." ") 322 | repeat 323 | Sleep(0.1) 324 | until IsAddonReady("SelectYesno") 325 | yield("/pcall SelectYesno true 0") 326 | repeat 327 | Sleep(0.1) 328 | until IsAddonReady("InputString") or IsPlayerAvailable() 329 | if IsPlayerAvailable() then 330 | retainer_named = true 331 | Echo("Successfully named retainer " .. retainer_name) 332 | else 333 | retainer_named = false 334 | Echo("Failed to name retainer " .. retainer_name .. ", trying another name") 335 | end 336 | end 337 | end 338 | 339 | function SetRetainerJobAndEquipItem(retainers) 340 | Movement(-124.45, 18.00, 20.78, 0.5) 341 | Target("Summoning Bell") 342 | Interact() 343 | repeat 344 | Sleep(0.1) 345 | until IsAddonReady("RetainerList") 346 | -- Find how many total retainers we're going over 347 | local total_retainers = 0 348 | for j = 1, #retainers do 349 | local retainer = retainers[j] 350 | local retainer_amount = retainer[2] 351 | total_retainers = total_retainers + retainer_amount 352 | --Sleep(0.0001) 353 | end 354 | -- Loop over each retainer and set their weapons 355 | for j = 0, total_retainers - 1 do 356 | local j_plus_one = j + 1 -- needed to make sure we pull the right thing from the retainer list 357 | local retainer = retainers[j_plus_one] 358 | local retainer_job = retainer[1] 359 | local retainer_amount = retainer[2] 360 | local job_details = GetJobDetails(retainer_job) 361 | if not job_details then 362 | Echo("Something went wrong when trying to get job_details while trying to set retainer classes") 363 | return 364 | end 365 | for k = 1, retainer_amount do 366 | Sleep(1) 367 | local retainer_name_text = GetNodeText("RetainerList", 2, k, 13) 368 | if retainer_name_text then -- check if there's actually a retainer in that slot 369 | yield("/pcall RetainerList true 2 " .. j) 370 | repeat 371 | Sleep(0.1) 372 | until IsAddonReady("SelectString") 373 | -- We need to find which node "Assign retainer class." is under 374 | local assign_class_node_id 375 | for i = 1, 10 do 376 | local text = GetNodeText("SelectString", 2, i , 3) 377 | if text == "Assign retainer class." then 378 | assign_class_node_id = i - 1 379 | break -- Exit the loop once the text is found 380 | end 381 | --Sleep(0.0001) 382 | end 383 | 384 | yield("/pcall SelectString true " .. assign_class_node_id) 385 | Sleep(0.3) 386 | repeat 387 | Sleep(0.1) 388 | until IsAddonReady("SelectString") 389 | yield("/pcall SelectString true " .. job_details.retainer_job_positon) 390 | repeat 391 | Sleep(0.1) 392 | until IsAddonReady("SelectYesno") 393 | yield("/pcall SelectYesno true 0") 394 | repeat 395 | Sleep(0.1) 396 | until IsAddonReady("SelectString") 397 | -- We need to find which node "View retainer attributes and gear. (No main arm equipped)" is under 398 | local gear_node_id 399 | for i = 1, 10 do 400 | local text = GetNodeText("SelectString", 2, i , 3) 401 | if text == "View retainer attributes and gear. (No main arm equipped)" then 402 | gear_node_id = i - 1 403 | break -- Exit the loop once the text is found 404 | end 405 | --Sleep(0.0001) 406 | end 407 | yield("/pcall SelectString true " .. gear_node_id) 408 | repeat 409 | Sleep(0.1) 410 | until IsAddonVisible("RetainerCharacter") 411 | -- make sure to move the right item, checks every inventory 412 | Sleep(1) 413 | 414 | local item_inventory_amount = GetItemCount(job_details.itemID, true) 415 | 416 | repeat 417 | Sleep(0.2) 418 | MoveItemToContainer(job_details.itemID, 0, 11000) -- Inventory tab 1 419 | Sleep(0.2) 420 | MoveItemToContainer(job_details.itemID, 1, 11000) -- Inventory tab 2 421 | Sleep(0.2) 422 | MoveItemToContainer(job_details.itemID, 2, 11000) -- Inventory tab 3 423 | Sleep(0.2) 424 | MoveItemToContainer(job_details.itemID, 3, 11000) -- Inventory tab 4 425 | Sleep(0.2) 426 | MoveItemToContainer(job_details.itemID, 3500, 11000) -- Armoury chest main hand 427 | until GetItemCount(job_details.itemID, true) == item_inventory_amount - 1 or GetItemCount(job_details.itemID, true) == 0 428 | Sleep(0.3) 429 | yield("/pcall RetainerCharacter true -1") 430 | repeat 431 | Sleep(0.1) 432 | until IsAddonReady("SelectString") 433 | yield("/pcall SelectString true 9") 434 | repeat 435 | Sleep(0.1) 436 | until IsAddonReady("RetainerList") 437 | else 438 | Echo("No retainer found") 439 | end 440 | end 441 | --Sleep(0.0001) 442 | end 443 | yield("/pcall RetainerList true -1") 444 | repeat 445 | Sleep(0.1) 446 | until IsPlayerAvailable() 447 | end 448 | 449 | for i = 1, #chars do 450 | local character = chars[i] 451 | local char_name = character["Character Name"] 452 | local retainers = character["Retainers"] 453 | if GetCharacterName(true) == char_name then 454 | -- Continue, no relogging needed 455 | else 456 | LogInfo("[MRET] Logging into character: "..char_name) 457 | RelogCharacter(char_name) 458 | Sleep(23.0) 459 | LoginCheck() 460 | LogInfo("[MRET] Logged in successfully") 461 | end 462 | yield("/at e") 463 | if MAKE_RETAINERS then 464 | -- Teleport and move to the retainer lady in limsa 465 | Teleporter("Limsa", "tp") 466 | Movement(-146.17, 18.21, 16.89) 467 | -- Attempt to create as many retainers as specified 468 | for j = 1, #retainers do 469 | local retainer = retainers[j] 470 | local retainer_amount = retainer[2] 471 | for k = 1, retainer_amount do 472 | CreateRetainer() 473 | end 474 | --Sleep(0.0001) 475 | end 476 | -- Now attempt to buy all the items needed for the specified jobs 477 | -- Move to West hawkers' alley 478 | Movement(-231.61, 16.00, 45.49) 479 | for j = 1, #retainers do 480 | local retainer = retainers[j] 481 | local retainer_job = retainer[1] 482 | local retainer_amount = retainer[2] 483 | BuyRetainerJobItem(retainer_job, retainer_amount) 484 | --Sleep(0.0001) 485 | end 486 | -- Move back to retainer place 487 | Movement(-123.85, 18.00, 20.58) 488 | end 489 | -- Do the venture quest 490 | if DO_VENTURE_QUEST then 491 | if CheckPluginsEnabled("Questionable") and not IsQuestComplete(66969) then 492 | Teleporter("Limsa", "tp") 493 | -- Let questionable do the venture quest 494 | DoQuest(1433) 495 | repeat 496 | Sleep(0.1) 497 | until IsQuestComplete(66969) 498 | yield("/qst stop") 499 | else 500 | Echo("Skipping venture quests since it's either completed or you're missing Questionable") 501 | end 502 | end 503 | -- Set job and equip the right items 504 | if MAKE_RETAINERS then 505 | SetRetainerJobAndEquipItem(retainers) 506 | end 507 | end 508 | 509 | if HasPlugin("YesAlready") then 510 | RestoreYesAlready() 511 | end -------------------------------------------------------------------------------- /Scripts/Retired Scripts/Collect items from main.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | ################################################################## 3 | ## What does this script do? ## 4 | ################################################################## 5 | 6 | -- You need to have Auto Retainer know who your characters are otherwise it will not work, to fix you will need to log into each missing character manually 7 | -- Optimal Dropbox settings are: Delay between trades, 4 // Trade open command throttle, 1554 8 | 9 | ]] 10 | 11 | -- ########### 12 | -- # CONFIGS # 13 | -- ########### 14 | 15 | -- Edit char_list.lua file for configuring characters 16 | 17 | local destination_server = "Louisoix" -- Server characters need to travel for collecting items 18 | local destination_aetheryte = "Limsa" -- Aetheryte that characters need to travel to for collecting items, case insensitive and you can be vague 19 | local destination_house = 0 -- Options: 0 = FC, 1 = Personal, 2 = Apartment 20 | local destination_type = 0 -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 21 | local path_home = true -- Options: true = Paths home from destination, false = Does nothing and logs out 22 | local do_movement = true -- Options: true = Paths to chosen character, false = Does nothing and waits for chosen character to come to you 23 | local use_external_character_list = true -- Options: true = Uses the external character list (char_list.lua), false = Uses the list you put in this file 24 | 25 | -- Usage: First Last 26 | -- This is your main character name, do not include @Server 27 | local main_char_name = "First Last" 28 | 29 | -- This is where you put your character list if you choose to not use the external one 30 | -- If use_external_character_list is set to true then this list is completely skipped 31 | -- Usage: First Last@Server, return_home, return_location 32 | -- return_home options: 0 = no, 1 = yes 33 | -- return_location options: 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 34 | -- This is where your alts that need items are listed 35 | local character_list_options = { 36 | { "First Last@Server", 0, 0 }, 37 | { "First Last@Server", 0, 0 } 38 | } 39 | 40 | -- ##################################### 41 | -- # DON'T TOUCH ANYTHING BELOW HERE # 42 | -- # UNLESS YOU KNOW WHAT YOU'RE DOING # 43 | -- ##################################### 44 | 45 | -- ################### 46 | -- # FUNCTION LOADER # 47 | -- ################### 48 | 49 | -- Edit char_list.lua file for configuring characters 50 | char_list = "vac_char_list.lua" 51 | 52 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 53 | vac_config_folder = snd_config_folder .. "\\VAC\\" 54 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 55 | LoadFunctions = loadfile(load_functions_file_location) 56 | LoadFunctions() 57 | LoadFileCheck() 58 | 59 | if not CheckPluginsEnabled("AutoRetainer", "TeleporterPlugin", "Lifestream", "PandorasBox", "SomethingNeedDoing", "TextAdvance", "vnavmesh") then 60 | return -- Stops script as plugins not available 61 | end 62 | 63 | LogInfo("[CIFM] ##############################") 64 | LogInfo("[CIFM] Starting script...") 65 | LogInfo("[CIFM] snd_config_folder: " .. snd_config_folder) 66 | LogInfo("[CIFM] char_list: " .. char_list) 67 | LogInfo("[CIFM] SNDConf+Char: " .. snd_config_folder .. "" .. char_list) 68 | LogInfo("[CIFM] ##############################") 69 | 70 | if use_external_character_list then 71 | local char_data = dofile(snd_config_folder .. char_list) 72 | character_list_options = char_data.character_list_options 73 | end 74 | 75 | local alt_char_name = "" 76 | 77 | -- ############### 78 | -- # MAIN SCRIPT # 79 | -- ############### 80 | 81 | local function ProcessAltCharacters(character_list_options, destination_server, destination_aetheryte, destination_type, destination_house, path_home) 82 | for i = 1, #character_list_options do 83 | -- Update alt character name 84 | local alt_char_name = character_list_options[i][1] 85 | 86 | -- Switch characters if required, looks up current character and compares 87 | if GetCharacterName(true) ~= character_list_options[i][1] then 88 | -- checks if return_location options matches 1 which returns player to Limsa 89 | if character_list_options[i][3] == 1 then 90 | if not (ZoneCheck("Limsa Lominsa Lower") or ZoneCheck("Limsa Lominsa Upper")) then 91 | Teleporter("Limsa", "tp") 92 | end 93 | end 94 | 95 | RelogCharacter(character_list_options[i][1]) 96 | Sleep(7.5) 97 | LoginCheck() 98 | end 99 | 100 | Echo("Picking up items from: " .. main_char_name) 101 | Echo("Processing " .. i .. "/" .. #character_list_options .. ", current character: " .. alt_char_name) 102 | 103 | -- Check if alt character on correct server 104 | yield("/li " .. destination_server) 105 | 106 | repeat 107 | Sleep(0.1) 108 | until GetCurrentWorld() == World_ID_List[destination_server].ID and IsPlayerAvailable() 109 | 110 | -- Alt character destination type, how alt char is travelling to the main 111 | -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 112 | if destination_type == 0 then 113 | dest_aetheryte_fullname = FindZoneIDByAetheryte(destination_aetheryte) 114 | 115 | -- If player is not at the destination then tp there 116 | if GetZoneID() ~= dest_aetheryte_fullname then 117 | Echo("Teleporting to " .. dest_aetheryte_fullname .. " to find " .. main_char_name) 118 | Teleporter(destination_aetheryte, "tp") 119 | else 120 | Echo("Already in the right zone to meet " .. main_char_name) 121 | end 122 | end 123 | 124 | -- Requires main added to friend list for access to estate list teleports 125 | -- Keeping it for future stuff 126 | if destination_type > 0 then 127 | Echo("Teleporting to estate to find " .. main_char_name) 128 | EstateTeleport(main_char_name, destination_house) 129 | end 130 | -- I really don't like the repeat of destination_type checking here, should probably be refactored into stuff above 131 | -- Handle different destination types 132 | -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 133 | if destination_type == 0 or destination_type == 1 then 134 | -- Waits until main char is present 135 | WaitUntilObjectExists(main_char_name) 136 | 137 | -- Paths to main char only if you have do_movement set to true 138 | if do_movement then 139 | -- Path to main char 140 | PathToObject(main_char_name, 3) 141 | end 142 | 143 | -- Invite main char to party, needs a target 144 | PartyInvite(main_char_name) 145 | 146 | elseif destination_type == 2 then 147 | -- If destination_type is 2, first go to the estate entrance, then to the main character 148 | PathToEstateEntrance() 149 | Interact() 150 | 151 | repeat 152 | Sleep(0.1) 153 | yield("/pcall SelectYesno true 0") 154 | until not IsAddonVisible("SelectYesno") 155 | 156 | -- Waits until main char is present 157 | WaitUntilObjectExists(main_char_name) 158 | 159 | -- Paths to main char only if you have do_movement set to true 160 | if do_movement then 161 | -- Path to main char 162 | PathToObject(main_char_name, 3) 163 | end 164 | 165 | -- Invite main char to party, needs a target 166 | PartyInvite(main_char_name) 167 | end 168 | 169 | -- Wait for the gil transfer to complete 170 | WaitForGilIncrease(1) 171 | 172 | -- Notify when all characters are finished 173 | if i == #character_list_options then 174 | Echo("Finished all " .. #character_list_options .. " characters") 175 | end 176 | 177 | -- Disband party once gil trigger has happened 178 | PartyDisband() 179 | 180 | -- Alt character handling to go home 181 | -- [2] return_home options: 0 = no, 1 = yes 182 | -- [3] return_location options: 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 183 | if path_home then 184 | if character_list_options[i][2] == 1 then 185 | ReturnHomeWorld() 186 | end 187 | 188 | -- Limsa stuff 189 | if character_list_options[i][3] == 1 then 190 | if not (ZoneCheck("Limsa Lominsa Lower") or ZoneCheck("Limsa Lominsa Upper")) then 191 | Echo("Attempting to go to Limsa") 192 | Teleporter("Limsa", "tp") 193 | end 194 | end 195 | 196 | -- Limsa Retainer Bell Stuff 197 | if character_list_options[i][3] == 2 then 198 | Echo("Attempting to go to Limsa retainer bell") 199 | PathToLimsaBell() 200 | end 201 | 202 | -- Nearby Retainer Bell Stuff 203 | if character_list_options[i][3] == 3 then 204 | Echo("Attempting to go to nearest retainer bell") 205 | Movement(GetObjectRawXPos("Summoning Bell"), GetObjectRawYPos("Summoning Bell"), GetObjectRawZPos("Summoning Bell")) 206 | end 207 | 208 | -- FC Entrance stuff 209 | if character_list_options[i][3] == 4 then 210 | Echo("Attempting to go to FC Entrance") 211 | Teleporter("Estate Hall (Free Company)", "tp") 212 | -- This likely needs some logic on nearest "Entrance" for nearby estates 213 | PathToEstateEntrance() 214 | end 215 | end 216 | end 217 | end 218 | 219 | ProcessAltCharacters(character_list_options, destination_server, destination_aetheryte, destination_type, destination_house, path_home) -------------------------------------------------------------------------------- /Scripts/Retired Scripts/Deliver GC Items.lua: -------------------------------------------------------------------------------- 1 | -- This script assumes you have all the items needed on all characters and delivers them to their gc 2 | -- This is a fully automated script 3 | -- You should use the Yes Already plugin to bypass the capped seals warning or it will break the script 4 | 5 | -- ########### 6 | -- # CONFIGS # 7 | -- ########### 8 | 9 | local use_external_character_list = true -- Options: true = uses the external character list in the same folder, default name being char_list.lua, false uses the list you put in this file 10 | local do_rankups = true -- Automatically attempts to rank up your gc if set to true 11 | 12 | -- This is where you put your character list if you choose to not use the external one (vac_char_list.lua) 13 | -- If use_external_character_list is set to true then this list is completely skipped 14 | local character_list = { 15 | "First Last@Server", 16 | "First Last@Server" 17 | } 18 | 19 | multi_char = true 20 | 21 | -- ##################################### 22 | -- # DON'T TOUCH ANYTHING BELOW HERE # 23 | -- # UNLESS YOU KNOW WHAT YOU'RE DOING # 24 | -- ##################################### 25 | 26 | char_list = "vac_char_list.lua" 27 | 28 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 29 | vac_config_folder = snd_config_folder .. "VAC\\" 30 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 31 | LoadFunctions = loadfile(load_functions_file_location) 32 | LoadFunctions() 33 | LoadFileCheck() 34 | 35 | if not CheckPluginsEnabled("AutoRetainer", "TeleporterPlugin", "Lifestream", "PandorasBox", "SomethingNeedDoing", "TextAdvance", "vnavmesh") then 36 | return -- Stops script as plugins not available 37 | end 38 | 39 | if HasPlugin("YesAlready") then 40 | PauseYesAlready() 41 | end 42 | 43 | LogInfo("[DGCI] ##############################") 44 | LogInfo("[DGCI] Starting script...") 45 | LogInfo("[DGCI] snd_config_folder: " .. snd_config_folder) 46 | LogInfo("[DGCI] char_list: " .. char_list) 47 | LogInfo("[DGCI] SNDConf+Char: " .. vac_config_folder .. "" .. char_list) 48 | LogInfo("[DGCI] ##############################") 49 | 50 | if use_external_character_list then 51 | local char_data = dofile(snd_config_folder .. char_list) -- Originally vac_config_folder but the file is used for other scripts in snd_config_folder 52 | character_list = char_data.character_list 53 | end 54 | 55 | -- ############# 56 | -- # DOL STUFF # 57 | -- ############# 58 | 59 | function DOL() 60 | local home_world = GetCurrentWorld() == GetHomeWorld() 61 | 62 | if not home_world then 63 | Teleporter(FindWorldByID(GetHomeWorld()), "li") 64 | Sleep(1.0) 65 | 66 | repeat 67 | Sleep(0.1) 68 | until not LifestreamIsBusy() and IsPlayerAvailable() 69 | 70 | -- Wait until the player is on the home world 71 | repeat 72 | Sleep(0.1) 73 | home_world = GetCurrentWorld() == GetHomeWorld() 74 | until home_world 75 | end 76 | 77 | -- Wait until the player is fully available 78 | repeat 79 | Sleep(0.1) 80 | until IsPlayerAvailable() 81 | 82 | Teleporter("gc", "li") 83 | 84 | repeat 85 | Sleep(0.1) 86 | until not LifestreamIsBusy() 87 | 88 | if do_rankups then 89 | local rankups_done = false 90 | while not rankups_done do 91 | local can_rankup = CanGCRankUp() 92 | if can_rankup then 93 | DoGcRankUp() 94 | else 95 | rankups_done = true 96 | end 97 | end 98 | end 99 | 100 | OpenGcSupplyWindow(1) 101 | GcProvisioningDeliver() 102 | CloseGcSupplyWindow() 103 | end 104 | 105 | -- ############### 106 | -- # MAIN SCRIPT # 107 | -- ############### 108 | 109 | function Main() 110 | DOL() 111 | end 112 | 113 | if multi_char then 114 | for _, char in ipairs(character_list) do 115 | if GetCharacterName(true) == char then 116 | -- continue, no relogging needed 117 | else 118 | RelogCharacter(char) 119 | Sleep(7.5) 120 | LoginCheck() 121 | end 122 | 123 | repeat 124 | Sleep(0.1) 125 | until IsPlayerAvailable() 126 | 127 | Main() 128 | end 129 | else 130 | Main() 131 | end 132 | 133 | if HasPlugin("YesAlready") then 134 | RestoreYesAlready() 135 | end -------------------------------------------------------------------------------- /Scripts/Retired Scripts/Generate list of items to gather.lua: -------------------------------------------------------------------------------- 1 | -- This script will generate a file in the SND_CONFIG_FOLDER which lists all the items you need to get to make the Deliver items to alt script fully automatic 2 | -- as long as you make sure you have all the items this script tells you to get you should be able to proceed without issue 3 | 4 | -- by default uses the output from the script that generates a provisioning_list 5 | -- probably don't touch this 6 | 7 | -- ########### 8 | -- # CONFIGS # 9 | -- ########### 10 | 11 | -- Configuration is not required for this file 12 | 13 | -- ##################################### 14 | -- # DON'T TOUCH ANYTHING BELOW HERE # 15 | -- # UNLESS YOU KNOW WHAT YOU'RE DOING # 16 | -- ##################################### 17 | 18 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 19 | vac_config_folder = snd_config_folder .. "\\VAC\\" 20 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 21 | LoadFunctions = loadfile(load_functions_file_location) 22 | LoadFunctions() 23 | LoadFileCheck() 24 | 25 | if not CheckPluginsEnabled("SomethingNeedDoing") then 26 | return -- Stops script as plugins not available 27 | end 28 | 29 | if HasPlugin("YesAlready") then 30 | PauseYesAlready() 31 | end 32 | 33 | provisioning_list_name_to_load = "provisioning_list.lua" 34 | 35 | local gc_config_folder = vac_config_folder .. "\\GC\\" 36 | dofile(gc_config_folder .. provisioning_list_name_to_load) 37 | 38 | local output_filename = "list_to_gather.txt" 39 | local output_folder = gc_config_folder 40 | 41 | EnsureFolderExists(output_folder) 42 | 43 | local function combine_items_by_category(provisioning_list) 44 | local category_totals = {} 45 | 46 | local category_names = { 47 | MIN = "Miner", 48 | BTN = "Botanist", 49 | FSH = "Fisher" 50 | } 51 | 52 | for _, data in pairs(provisioning_list) do 53 | for category, item_data in pairs(data) do 54 | if type(item_data) == "table" and item_data["Item"] then 55 | local item_name = item_data["Item"] 56 | local item_qty = tonumber(item_data["QTY"]) 57 | local category_name = category_names[category] or category 58 | 59 | if not category_totals[category_name] then 60 | category_totals[category_name] = {} 61 | end 62 | 63 | if not category_totals[category_name][item_name] then 64 | category_totals[category_name][item_name] = 0 65 | end 66 | 67 | category_totals[category_name][item_name] = category_totals[category_name][item_name] + item_qty 68 | end 69 | end 70 | end 71 | 72 | return category_totals 73 | end 74 | 75 | local function create_character_summary(provisioning_list) 76 | local summaries = {} 77 | 78 | for character_name, data in pairs(provisioning_list) do 79 | local character_summary = {} 80 | for category, item_data in pairs(data) do 81 | if type(item_data) == "table" and item_data["Item"] then 82 | table.insert(character_summary, item_data["Item"] .. ": " .. item_data["QTY"]) 83 | end 84 | end 85 | summaries[character_name] = character_summary 86 | end 87 | 88 | return summaries 89 | end 90 | 91 | local function write_to_file(category_totals, character_summaries, filename) 92 | local file = io.open(filename, "w") 93 | if not file then 94 | return 95 | end 96 | 97 | file:write("************************\n") 98 | file:write("* Provisioning Summary *\n") 99 | file:write("************************\n\n") 100 | 101 | -- Job ordering 102 | local job_order = { "Miner", "Botanist", "Fisher" } 103 | local remaining_categories = {} 104 | 105 | -- Separate order categories and gather remaining ones 106 | for category in pairs(category_totals) do 107 | if not table.concat(job_order):find(category) then 108 | table.insert(remaining_categories, category) 109 | end 110 | end 111 | 112 | -- Sort remaining categories a-z 113 | table.sort(remaining_categories) 114 | 115 | -- Combine ordered categories with the sorted remaining ones 116 | local sorted_categories = {} 117 | 118 | for _, category in ipairs(job_order) do 119 | if category_totals[category] then 120 | table.insert(sorted_categories, category) 121 | end 122 | end 123 | 124 | for _, category in ipairs(remaining_categories) do 125 | table.insert(sorted_categories, category) 126 | end 127 | 128 | -- Write categories to file 129 | for _, category in ipairs(sorted_categories) do 130 | local items = category_totals[category] 131 | file:write(category .. "\n") 132 | file:write(string.rep("=", #category + 4) .. "\n") 133 | 134 | -- Sort items a-z 135 | local sorted_items = {} 136 | 137 | for item in pairs(items) do 138 | table.insert(sorted_items, item) 139 | end 140 | table.sort(sorted_items) 141 | 142 | for _, item in ipairs(sorted_items) do 143 | local qty = items[item] 144 | file:write(item .. ": " .. qty .. "\n") 145 | end 146 | file:write("\n") 147 | end 148 | 149 | file:write("******************************\n") 150 | file:write("* Per Character Requirements *\n") 151 | file:write("******************************\n\n") 152 | 153 | -- Sort character names a-z 154 | local sorted_characters = {} 155 | 156 | for character_name in pairs(character_summaries) do 157 | table.insert(sorted_characters, character_name) 158 | end 159 | table.sort(sorted_characters) 160 | 161 | for _, character_name in ipairs(sorted_characters) do 162 | local summary = character_summaries[character_name] 163 | file:write(character_name .. "\n") 164 | file:write(string.rep("-", #character_name + 4) .. "\n") 165 | 166 | for _, item_line in ipairs(summary) do 167 | file:write(item_line .. "\n") 168 | end 169 | file:write("\n") 170 | end 171 | 172 | file:close() 173 | end 174 | 175 | 176 | local combined_items_by_category = combine_items_by_category(provisioning_list) 177 | local character_summaries = create_character_summary(provisioning_list) 178 | 179 | write_to_file(combined_items_by_category, character_summaries, output_folder .. output_filename) 180 | 181 | if HasPlugin("YesAlready") then 182 | RestoreYesAlready() 183 | end -------------------------------------------------------------------------------- /Scripts/Retired Scripts/README.md: -------------------------------------------------------------------------------- 1 | # Retired Scripts 2 | 3 | ![Status](https://img.shields.io/badge/status-retired-lightgrey) 4 | 5 | Where scripts of the past lay to rest. 6 | 7 | Anything we used to maintain but no longer do due to better scripts being made or no longer having a purpose. 8 | 9 | Might or might not work, no support will be given for scripts here. 10 | -------------------------------------------------------------------------------- /Scripts/Retired Scripts/dol leveller.lua: -------------------------------------------------------------------------------- 1 | -- Ideally used with The Road to 90 buff, otherwise it will take double the amount for everything 2 | -- You need approx 2m gil per character you wish to level through this with The Road to 90, probably 4mil with no buff (no clue, you won't have the double xp though) 3 | -- You likely only need around 20-30 per item it asks for, fish 2-3, very unlikely you need more than that, don't spend more than 20k or try not to 4 | -- Maybe don't bother doing Fisher, mb prices get too high around level 50 onwards. Probably better to just do Ocean Fishing if you value gil. 5 | -- This is not a full automated script (yet, maybe maybe not) 6 | -- It will teleport you to a market board, you are required to purchase the items the GC asks for, after that it will auto turnin and log off, you will need to start the script again for additional characters 7 | -- If the market board does not have the item you need, stop the script and go to another world, start the script again 8 | -- Closing the market board early doesn't matter either, cancel the tp and buy items, then /tp limsa 9 | -- You should use the Yes Already plugin to bypass the capped seals warning or it will break the script 10 | 11 | --########### 12 | --# CONFIGS # 13 | --########### 14 | 15 | -- this toggle allows you to run the script on as many characters as you'd like, it'll rotate between them 16 | MULTICHAR = false 17 | 18 | CharList = "CharList.lua" 19 | 20 | --##################################### 21 | --# DON'T TOUCH ANYTHING BELOW HERE # 22 | --# UNLESS YOU KNOW WHAT YOU'RE DOING # 23 | --##################################### 24 | 25 | SNDConfigFolder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 26 | LoadFunctionsFileLocation = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 27 | LoadFunctions = loadfile(LoadFunctionsFileLocation) 28 | LoadFunctions() 29 | LoadFileCheck() 30 | 31 | --############## 32 | -- DOL STUFF 33 | --############## 34 | 35 | function DOL() 36 | OpenTimers() 37 | Teleporter("Ul'dah", "tp") 38 | ZoneTransitions() 39 | yield("/li mb") 40 | ZoneTransitions() 41 | MarketBoardChecker() -- should probably add auto buying here or something 42 | Teleporter("Limsa", "tp") 43 | ZoneTransitions() 44 | yield("/li Aftcastle") 45 | ZoneTransitions() 46 | Movement(93.00, 40.27, 75.60) 47 | OpenGcSupplyWindow(1) 48 | GcProvisioningDeliver(3) 49 | CloseGcSupplyWindow() 50 | LogOut() 51 | end 52 | 53 | --############### 54 | --# MAIN SCRIPT # 55 | --############### 56 | 57 | function Main() 58 | DOL() 59 | end 60 | 61 | if MULTICHAR then 62 | for _, char in ipairs(character_list) do 63 | if GetCharacterName(true) == char then 64 | -- continue, no relogging needed 65 | else 66 | RelogCharacter(char) 67 | Sleep(15.0) 68 | LoginCheck() 69 | end 70 | repeat 71 | Sleep(0.1) 72 | until IsPlayerAvailable() 73 | Main() 74 | end 75 | else 76 | Main() 77 | end -------------------------------------------------------------------------------- /Scripts/Retired Scripts/recast timers.lua: -------------------------------------------------------------------------------- 1 | function RecastTimes() 2 | local ability_id = 4 3 | local recast_functions = { 4 | ["GetRecastTimeElapsed"] = GetRecastTimeElapsed(ability_id), 5 | ["GetRealRecastTimeElapsed"] = GetRealRecastTimeElapsed(ability_id), 6 | ["GetRecastTime"] = GetRecastTime(ability_id), 7 | ["GetRealRecastTime"] = GetRealRecastTime(ability_id), 8 | ["GetSpellCooldown"] = GetSpellCooldown(ability_id), 9 | ["GetRealSpellCooldown"] = GetRealSpellCooldown(ability_id), 10 | ["GetSpellCooldownInt"] = GetSpellCooldownInt(ability_id) 11 | } 12 | 13 | for name, value in pairs(recast_functions) do 14 | yield("/e " .. name .. ": " .. tostring(value)) 15 | end 16 | end 17 | 18 | RecastTimes() 19 | -------------------------------------------------------------------------------- /Scripts/Retired Scripts/zone finder.lua: -------------------------------------------------------------------------------- 1 | zone = GetZoneID() 2 | 3 | yield("/echo " .. zone) -------------------------------------------------------------------------------- /Scripts/Tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | | Script Name | Description | Status | 4 | |-------------|-------------|-------------| 5 | | Items for FC Rank 6 | Calculates items needed for FC rank 6 | ![Status](https://img.shields.io/badge/status-working-brightgreen) | 6 | | Mail Opener | Automates mail management | ![Status](https://img.shields.io/badge/status-needs_testing-blue) | 7 | | Pos Finder | Displays and logs current position | ![Status](https://img.shields.io/badge/status-working-brightgreen) | -------------------------------------------------------------------------------- /Scripts/Tools/items for fc rank 6.lua: -------------------------------------------------------------------------------- 1 | -- Acceptable items include all gear with names that are not yellow in their help window. Items must be of Aetherial, Green, or Blue rarity. 2 | -- In addition, the item must be sellable to vendors, which is indicated by a "Sells for" value in its tooltip. 3 | -- For GC seals, there is no difference in reward between normal quality and high quality gear, although an additional confirmation prompt will appear if the player selects a piece of HQ equipment to trade. 4 | -- For Company Credits, HQ items yield double the amount when compared to NQ items, so it is beneficial to ensure the item you trade in is HQ. 5 | 6 | function ItemsForFcRank6() 7 | local ilvl = 640 -- Item level 8 | local is_hq = true -- Options: true = HQ, false = NQ 9 | 10 | -- Check if ilvl is correctly selected 11 | if not ilvl or ilvl <= 0 then 12 | yield("/e Invalid item level.") 13 | yield("/e Stopping script.") 14 | return nil 15 | end 16 | 17 | -- Check if is_hq is correctly selected 18 | if is_hq ~= true and is_hq ~= false then 19 | yield("/e Invalid HQ value, defaulting to NQ.") 20 | is_hq = false 21 | end 22 | 23 | -- Check if the player is on their home world 24 | if GetCurrentWorld() ~= GetHomeWorld() then 25 | yield("/e You are not on your home world.") 26 | yield("/e Stopping script.") 27 | return nil 28 | end 29 | 30 | -- Check if the player is in a Free Company 31 | local fc_rank = GetFCRank() 32 | if not fc_rank or fc_rank < 1 then 33 | yield("/e You are not in an FC.") 34 | yield("/e Stopping script.") 35 | return nil 36 | end 37 | 38 | -- Open the Free Company menu to update Company Credit amount 39 | repeat 40 | yield("/freecompanycmd") 41 | yield("/wait 0.1") 42 | until IsAddonVisible("FreeCompany") 43 | 44 | yield("/wait 0.5") 45 | 46 | -- Fetch current Free Company credits 47 | local fc_node_credits = tonumber(((GetNodeText("FreeCompany", 15) or ""):gsub(",", ""))) or 0 48 | 49 | -- Close the Free Company menu 50 | repeat 51 | yield("/freecompanycmd") 52 | yield("/wait 0.1") 53 | until not IsAddonVisible("FreeCompany") 54 | 55 | -- Define the credit amounts required for each rank (Rank 1 to Rank 6) 56 | local fc_rank_credits = { 57 | [1] = 0, -- Rank 1 credits 58 | [2] = 3700, -- Rank 2 credits 59 | [3] = 15300, -- Rank 3 credits 60 | [4] = 33300, -- Rank 4 credits 61 | [5] = 59300, -- Rank 5 credits 62 | [6] = 89300 -- Rank 6 credits 63 | } 64 | 65 | -- Ensure the correct current credits value 66 | local current_credits = fc_node_credits 67 | 68 | -- If the FC credits are less than the current rank credits, use the required credits amount for that rank instead 69 | if fc_node_credits > fc_rank_credits[fc_rank] then 70 | current_credits = fc_node_credits 71 | else 72 | current_credits = fc_rank_credits[fc_rank] 73 | end 74 | 75 | -- Calculate seals amount based on item level 76 | local function CalculateSealsAmount(ilvl) 77 | if ilvl <= 200 then 78 | return 5.75 * ilvl 79 | elseif ilvl <= 400 then 80 | return 2 * ilvl + 750 81 | elseif ilvl <= 530 then 82 | return 1.75 * ilvl + 850.5 83 | elseif ilvl <= 660 then 84 | return 1.6667 * ilvl + 895 85 | elseif ilvl <= 790 then 86 | return ilvl + 1339 87 | else 88 | return 0 89 | end 90 | end 91 | 92 | -- Calculate the company credit amount based on item quality 93 | local function CalculateCreditAmount(ilvl, is_hq) 94 | if is_hq then 95 | return ilvl * 3 -- HQ items: ilvl * 3 96 | else 97 | return ilvl * 1.5 -- NQ items: ilvl * 1.5 98 | end 99 | end 100 | 101 | -- Get the required credits for rank 6 102 | local rank_6_credits = fc_rank_credits[6] 103 | 104 | -- Calculate how many credits are needed to reach rank 6 105 | local credits_needed = rank_6_credits - current_credits 106 | 107 | -- Calculate the seals amount for the given ilvl 108 | local seals_amount = CalculateSealsAmount(ilvl) 109 | 110 | -- Calculate the credit amount for the given ilvl and item quality 111 | local credit_amount = CalculateCreditAmount(ilvl, is_hq) 112 | 113 | -- Calculate the number of items needed to reach rank 6 114 | local items_needed = credits_needed / credit_amount 115 | 116 | -- Return the result (rounded up to ensure whole items) 117 | return math.ceil(items_needed) 118 | end 119 | 120 | local items_needed = ItemsForFcRank6() 121 | 122 | if items_needed then 123 | yield("/e Items needed: " .. items_needed) 124 | end -------------------------------------------------------------------------------- /Scripts/Tools/mail opener.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | __ __ _ _ ___ 3 | | \/ | __ _(_)| | / _ \ _ __ ___ _ __ ___ _ __ 4 | | |\/| |/ _` | || | | | | | '_ \ / _ \ '_ \ / _ \ '__| 5 | | | | | (_| | || | | |_| | |_) | __/ | | | __/ | 6 | |_| |_|\__,_|_||_| \___/| .__/ \___|_| |_|\___|_| 7 | |_| 8 | #################### 9 | ## Version ## 10 | ## 1.0.3 ## 11 | #################### 12 | 13 | -> 1.0.0: Initial release 14 | 15 | -> 1.0.1: 16 | - Fixed disabling Text Advance 17 | - Potentially fixed exiting out of the "LetterList" addon if stuck 18 | 19 | -> 1.0.2: 20 | - Added checks to every repeat to prevent getting stuck 21 | - Increased Sleep() times to help with stability 22 | - Disabled RequestLetter() function as it tends to get stuck (for me at least) 23 | - Added re-enabling Text Advance 24 | 25 | -> 1.0.3: 26 | - Small tweak to enable all letterboxes 27 | 28 | #################################################### 29 | ## Description ## 30 | #################################################### 31 | 32 | https://github.com/WigglyMuffin/SNDScripts 33 | Tweaked by Friendly <3 34 | 35 | This script automatically opens all of your characters mail 36 | It will also request additional mail if the setting is enabled 37 | There is no movement, so it is assumed you are outside somewhere that can view your mail 38 | 39 | #################################################### 40 | ## Requirements ## 41 | #################################################### 42 | 43 | -> Something Need Doing (Expanded Edition) : https://puni.sh/api/repository/croizat 44 | 45 | #################################################### 46 | ## Settings ## 47 | ##################################################]] 48 | 49 | local item_accept_wait_time = 4.5 -- Increase this if you have issues 50 | local wait_for_request = true -- Waits for requested mail. Options: true = will wait for requested mail, false = will not wait for requested mail 51 | 52 | --[[################################################ 53 | ## Script Start ## 54 | ##################################################]] 55 | 56 | if HasPlugin("YesAlready") then 57 | PauseYesAlready() 58 | end 59 | 60 | if HasPlugin("TextAdvance") then 61 | yield("/at n") 62 | end 63 | 64 | function Target(target) 65 | if DoesObjectExist(target) then 66 | local target_command = "/target \"" .. target .. "\"" 67 | attempts = 0 68 | maxattempts = 10 69 | repeat 70 | yield(target_command) 71 | attempts = attempts + 1 72 | Sleep(0.2) 73 | until string.lower(GetTargetName()) == string.lower(target) or attempts >= maxattempts 74 | return true 75 | else 76 | return false 77 | end 78 | end 79 | 80 | function Sleep(time) 81 | yield("/wait " .. tostring(time)) 82 | end 83 | 84 | function Interact() 85 | attempts = 0 86 | maxattempts = 10 87 | repeat 88 | attempts = attempts + 1 89 | Sleep(0.21) 90 | until (IsPlayerAvailable() and not IsPlayerCasting() and not GetCharacterCondition(26) and not IsMoving()) or GetCharacterCondition(32) or attempts >= maxattempts 91 | 92 | Dismount() 93 | Sleep(0.5) 94 | yield("/interact") 95 | Sleep(1) 96 | attempts = 0 97 | maxattempts = 10 98 | repeat 99 | Sleep(0.211) 100 | attempts = attempts + 1 101 | until not IsPlayerCasting() or attempts >= maxattempts 102 | end 103 | 104 | function Dismount() 105 | if TerritorySupportsMounting() then 106 | if GetCharacterCondition(4) then 107 | attempts = 0 108 | maxattempts = 10 109 | repeat 110 | yield("/mount") 111 | Sleep(0.212) 112 | until not GetCharacterCondition(4) or attempts >= maxattempts 113 | end 114 | 115 | attempts = 0 116 | maxattempts = 10 117 | repeat 118 | Sleep(0.213) 119 | attempts = attempts + 1 120 | until IsPlayerAvailable() and not IsPlayerCasting() or attempts >= maxattempts 121 | else 122 | -- do nothing 123 | end 124 | end 125 | 126 | local function OpenLetterMenu() 127 | if not IsAddonVisible("LetterList") then 128 | -- List of possible targets 129 | local targets = { "Delivery Moogle", "Regal Letter Box", "Moogle Letter Box" } 130 | 131 | -- Try to target each one in sequence 132 | for _, target_name in ipairs(targets) do 133 | if Target(target_name) then 134 | break -- Exit the loop once a target is found 135 | end 136 | end 137 | 138 | Interact() 139 | 140 | attempts = 0 141 | maxattempts = 10 142 | repeat 143 | attempts = attempts + 1 144 | Sleep(0.214) 145 | until IsAddonReady("Talk") or attempts >= maxattempts 146 | 147 | attempts = 0 148 | maxattempts = 10 149 | repeat 150 | yield("/callback Talk true 0") 151 | attempts = attempts + 1 152 | Sleep(0.215) 153 | until not IsAddonVisible("Talk") or attempts >= maxattempts 154 | 155 | attempts = 0 156 | maxattempts = 10 157 | repeat 158 | attempts = attempts + 1 159 | Sleep(0.216) 160 | until IsAddonReady("LetterList") or attempts >= maxattempts 161 | 162 | -- Handle the "SelectOk" window with a check to prevent getting stuck 163 | 164 | local max_attempts = 10 165 | local attempts = 0 166 | repeat 167 | if IsAddonReady("SelectOk") and string.match(GetNodeText("SelectOk", 3), "You cannot carry any more campaign") then 168 | yield("/callback SelectOk true 0") 169 | break 170 | end 171 | attempts = attempts + 1 172 | 173 | if attempts >= max_attempts then 174 | break 175 | end 176 | Sleep(0.217) 177 | until IsAddonVisible("SelectOk") and IsAddonVisible("LetterList") or attempts >= maxattempts 178 | attempts = 0 179 | maxattempts = 10 180 | repeat 181 | Sleep(0.218) 182 | attempts = attempts + 1 183 | until IsAddonReady("LetterList") and string.match(GetNodeText("LetterList", 14, 13, 2), "Purchases & Rewards") or attempts >= maxattempts 184 | end 185 | end 186 | 187 | local function SelectLetter() 188 | -- Check if "LetterList" addon is ready 189 | attempts = 0 190 | maxattempts = 10 191 | repeat 192 | Sleep(0.219) 193 | attempts = attempts + 1 194 | until IsAddonReady("LetterList") or attempts >= maxattempts 195 | 196 | -- Selects the first letter in the letter list 197 | attempts = 0 198 | maxattempts = 10 199 | repeat 200 | yield("/callback LetterList true 0 0") 201 | Sleep(0.22) 202 | attempts = attempts + 1 203 | until IsAddonVisible("LetterViewer") or attempts >= maxattempts 204 | 205 | -- If "LetterList" breaks, timeout to recover opening remaining letters 206 | 207 | local max_attempts = 10 208 | local attempts = 0 209 | repeat 210 | yield("/callback LetterList true 0 0") 211 | Sleep(0.221) 212 | attempts = attempts + 1 213 | 214 | if attempts >= max_attempts then 215 | attempts = 0 216 | maxattempts = 10 217 | repeat 218 | yield("/callback LetterList true -1") 219 | attempts = attempts + 1 220 | until not IsAddonVisible("LetterList") or attempts >= maxattempts 221 | OpenLetterMenu() 222 | return 223 | end 224 | 225 | Sleep(0.222) 226 | until IsAddonVisible("LetterViewer") or attempts >= maxattempts 227 | end 228 | 229 | local function TakeLetterContents() 230 | 231 | -- Check if "LetterViewer" addon is ready 232 | attempts = 0 233 | maxattempts = 10 234 | repeat 235 | Sleep(0.223) 236 | attempts = attempts + 1 237 | until IsAddonReady("LetterViewer") or attempts >= maxattempts 238 | 239 | -- If letter contains "Enclosed" then take items 240 | -- This also needs visibility check if it gets added here 241 | --if string.match(GetNodeText("LetterViewer", 28), "Enclosed") and IsNodeVisible("LetterViewer", 1, 2, 5) then 242 | yield("/callback LetterViewer true 1") 243 | yield("/callback LetterViewer true 1") 244 | yield("/callback LetterViewer true 1") 245 | --end 246 | Sleep(1) 247 | end 248 | 249 | local function DeleteLetter() 250 | 251 | -- Check if "LetterViewer" addon is ready 252 | attempts = 0 253 | maxattempts = 10 254 | repeat 255 | Sleep(0.224) 256 | attempts = attempts + 1 257 | until IsAddonReady("LetterViewer") or attempts >= maxattempts 258 | 259 | -- Track whether letter has been deleted 260 | local deleted_letter = false 261 | 262 | -- Check whether letter has text and node visibility, then delete the letter 263 | attempts = 0 264 | maxattempts = 10 265 | repeat 266 | if IsAddonReady("LetterViewer") and string.match(GetNodeText("LetterViewer", 28), ".+") then 267 | attempts = 0 268 | maxattempts = 10 269 | repeat 270 | yield("/callback LetterViewer true 2") 271 | Sleep(0.225) 272 | attempts = attempts + 1 273 | until IsAddonReady("SelectYesno") and string.match(GetNodeText("SelectYesno", 15), "Delete this letter?") or attempts >= maxattempts 274 | yield("/callback SelectYesno true 0") 275 | end 276 | Sleep(0.226) 277 | attempts = attempts + 1 278 | until (not IsAddonVisible("LetterViewer") and IsAddonVisible("LetterList")) or attempts >= maxattempts 279 | end 280 | 281 | local function RequestLetter() 282 | 283 | -- Check if "LetterList" addon is ready 284 | attempts = 0 285 | maxattempts = 10 286 | repeat 287 | Sleep(0.227) 288 | attempts = attempts + 1 289 | until IsAddonReady("LetterList") or attempts >= maxattempts 290 | 291 | attempts = 0 292 | maxattempts = 10 293 | repeat 294 | yield("/callback LetterList true 3") 295 | Sleep(0.228) 296 | attempts = attempts + 1 297 | until IsAddonReady("SelectYesno") and string.match(GetNodeText("SelectYesno", 15), "Send a request to have recently acquired special") or attempts >= maxattempts 298 | 299 | attempts = 0 300 | maxattempts = 10 301 | repeat 302 | attempts = attempts + 1 303 | yield("/callback SelectYesno true 0") 304 | Sleep(0.229) 305 | until not IsAddonVisible("SelectYesno") and IsAddonVisible("LetterList") or attempts >= maxattempts 306 | end 307 | 308 | -- Flag whether wait for request has been triggered 309 | wait_for_request_triggered = false -- Improve this if GetMailQuantity gets added 310 | 311 | function Main() 312 | OpenLetterMenu() 313 | 314 | local letter_quantity = string.match(GetNodeText("LetterList", 3), "(%d+)") 315 | 316 | for i = 1, letter_quantity do 317 | SelectLetter() 318 | Sleep(1) 319 | TakeLetterContents() 320 | if IsAddonVisible("LetterViewer") then 321 | if IsNodeVisible("LetterViewer", 1, 14, 20) or IsNodeVisible("LetterViewer", 1, 2, 5) then 322 | Sleep(item_accept_wait_time) -- Improve this if RGBA gets added 323 | end 324 | end 325 | DeleteLetter() 326 | end 327 | 328 | -- RequestLetter() 329 | 330 | -- Improve this if GetMailQuantity gets added 331 | if wait_for_request and not wait_for_request_triggered then 332 | yield("/callback LetterList true -1") 333 | wait_for_request_triggered = true 334 | Sleep(1.0) 335 | Main() 336 | end 337 | end 338 | 339 | Main() 340 | Sleep(1) 341 | if IsAddonVisible("LetterList") then 342 | attempts = 0 343 | maxattempts = 10 344 | repeat 345 | attempts = attempts + 1 346 | yield("/callback LetterList true -1") 347 | until not IsAddonVisible("LetterList") or attempts >= maxattempts 348 | end 349 | 350 | if HasPlugin("YesAlready") then 351 | RestoreYesAlready() 352 | end 353 | 354 | if HasPlugin("TextAdvance") then 355 | yield("/at y") 356 | end 357 | -------------------------------------------------------------------------------- /Scripts/Tools/pos finder.lua: -------------------------------------------------------------------------------- 1 | XPOS = string.format("%.2f", GetPlayerRawXPos()) 2 | YPOS = string.format("%.2f", GetPlayerRawYPos()) 3 | ZPOS = string.format("%.2f", GetPlayerRawZPos()) 4 | yield("/echo " .. XPOS .. ", " .. YPOS .. ", " .. ZPOS) -------------------------------------------------------------------------------- /Scripts/Trading Scripts/Kupo Box CharListGen.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | ############################################################ 4 | ## Kupo Box ## 5 | ## Character List Generator ## 6 | ############################################################ 7 | 8 | 9 | #################### 10 | ## Version ## 11 | ## 1.1.0 ## 12 | #################### 13 | 14 | -> 1.0.0: Initial release 15 | - Basic functionality to generate character list for Kupo Box 16 | - Support for multiple characters and trading partners 17 | 18 | -> 1.0.1: Enhanced functionality 19 | - Added support for more trading partners than characters 20 | - Implemented cyclic character assignment when there are more trading partners 21 | 22 | -> 1.0.2: Major update to improve flexibility and usability 23 | - Reworked logic to handle various trading scenarios: 24 | * Single main character trading with multiple partners 25 | * Multiple characters trading with multiple partners 26 | - Improved handling of gen_char_list and trading_with_list: 27 | * If gen_char_list has one entry, it's used as the main trading character for all partners 28 | * If gen_char_list has multiple entries, they're paired with trading_with_list entries 29 | - Enhanced server destination logic: 30 | * Added set_destination_server_to_home_server option for automatic server assignment 31 | - Refined code structure for better readability and maintenance 32 | - Updated comments and variable names for clarity 33 | 34 | -> 1.1.0: Comprehensive revision for correct list handling and enhanced flexibility 35 | - Corrected the roles of gen_char_list and trading_with_list: 36 | * gen_char_list now represents the "Trading With" entries 37 | * trading_with_list now represents the "Name" entries 38 | - Implemented flexible entry generation based on the larger of the two lists 39 | - Added support for all possible list combinations: 40 | * Single entry in gen_char_list with multiple entries in trading_with_list 41 | * Multiple entries in gen_char_list with fewer entries in trading_with_list 42 | * Equal number of entries in both lists 43 | - Improved cyclic assignment logic to handle any list size discrepancy 44 | - Maintained compatibility with existing server destination and movement options 45 | - Further refined code structure and comments for improved clarity and maintainability 46 | 47 | #################################################### 48 | ## Description ## 49 | #################################################### 50 | 51 | The Kupo Box Character List Generator is a versatile Lua script designed to streamline the process of creating character configurations for Kupo Box. 52 | 53 | Key Features: 54 | 1. Flexible Character Management: Supports configuration for multiple characters and trading partners. 55 | 2. Dynamic Trading Scenarios: Handles various setups, including one-to-many and many-to-many trading. 56 | 3. Server Destination Logic: Includes an option to automatically set destination servers based on characters' home servers. 57 | 4. Customisable Trading Parameters: Allows specification of trading locations, movement options, and return behaviours. 58 | 5. Item Configuration: Supports detailed item listings for each character, including item names and quantities. 59 | 6. Output Compatibility: Generates a Lua table (character_list_kupobox.lua) that can be directly inserted into vac_char_list or Kupo Box configurations. 60 | 61 | This script is ideal for players managing multiple characters or complex trading arrangements, offering a powerful tool to automate and organise character setups for efficient item exchanges. 62 | 63 | #################################################### 64 | ## Required Plugins ## 65 | #################################################### 66 | 67 | -> SomethingNeedDoing 68 | 69 | ##################### 70 | ## Settings ## 71 | ###################]] 72 | 73 | -- Set the characters you're generating a list with, the list generates in order 74 | -- If only one character is listed, it will be used as the main trading partner for all entries in trading_with_list 75 | local gen_char_list = { 76 | "Mrow Mrow@Louisoix", -- Main trading character 77 | -- "Smol Meow@Lich", -- Uncomment to add more main trading characters 78 | -- "Beeg Meow@Zodiark" -- Uncomment to add more main trading characters 79 | } 80 | 81 | -- Here you can define a list of trading partners. 82 | -- If gen_char_list has only one entry, this list determines the number of entries generated. 83 | local trading_with_list = { 84 | "Mrow Mrow@Louisoix", -- Trading partner 1 for main trading character 85 | "Smol Meow@Lich", -- Trading partner 2 for main trading character 86 | "Beeg Meow@Zodiark" -- Trading partner 3 for main trading character 87 | } 88 | 89 | -- Here you set the default settings each character will have when generated 90 | 91 | local destination_server = "Zodiark" -- Set this to the server you're meeting the delivery character on 92 | local destination_type = 0 -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 93 | local destination_aetheryte = "Aleport" -- Aetheryte to meet at if ["Destination Type"] is set to 0 94 | local destination_house = 0 -- Options: 0 = FC, 1 = Personal, 2 = Apartment // Only active if ["Destination Type"] is set to 1 or 2 95 | local do_movement = true -- Options: true, false // will move to the character you're trading to, usually this is done by the delivery character 96 | local return_home = false -- Options: true, false // will just log out if set to false, otherwise will move to home server and to set location configured by ["Return Location"] 97 | local return_location = 0 -- Options: 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 98 | 99 | -- This option if set to true will override destination_server and set it to that chars home server 100 | -- If the list is in order it can be used to make everything faster as the characters do not have to travel anywhere, 101 | -- they just meet the trader on their server at the set location 102 | local set_destination_server_to_home_server = false 103 | 104 | --[[################################# 105 | # DON'T TOUCH ANYTHING BELOW HERE # 106 | # UNLESS YOU KNOW WHAT YOU'RE DOING # 107 | ##################################### 108 | 109 | ################### 110 | # FUNCTION LOADER # 111 | #################]] 112 | 113 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 114 | vac_config_folder = snd_config_folder .. "\\VAC\\" 115 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 116 | LoadFunctions = loadfile(load_functions_file_location) 117 | LoadFunctions() 118 | LoadFileCheck() 119 | 120 | if not CheckPluginsEnabled("SomethingNeedDoing") then 121 | return -- Stops script as plugins not available 122 | end 123 | 124 | if HasPlugin("YesAlready") then 125 | PauseYesAlready() 126 | end 127 | 128 | --[[########### 129 | # MAIN SCRIPT # 130 | #############]] 131 | 132 | local function extract_world_from_name(char_name) 133 | local at_position = string.find(char_name, "@") 134 | if at_position then 135 | return string.sub(char_name, at_position + 1) 136 | end 137 | return nil 138 | end 139 | 140 | local function strip_after_at(input_string) 141 | local result = string.match(input_string, "([^@]+)") 142 | return result 143 | end 144 | 145 | local function generate_character_list_options() 146 | local character_list_options = {} 147 | local num_chars = #gen_char_list 148 | local num_trading_partners = #trading_with_list 149 | 150 | local entries_to_generate = math.max(num_chars, num_trading_partners) 151 | 152 | for i = 1, entries_to_generate do 153 | local trading_with_index = ((i - 1) % num_chars) + 1 154 | local name_index = ((i - 1) % num_trading_partners) + 1 155 | 156 | local char_name = trading_with_list[name_index] 157 | local trading_with_t = strip_after_at(gen_char_list[trading_with_index]) 158 | 159 | local server_to_use = destination_server 160 | 161 | -- If set_destination_server_to_home_server is true, extract the world from the character name 162 | if set_destination_server_to_home_server then 163 | server_to_use = extract_world_from_name(char_name) or destination_server 164 | end 165 | 166 | -- Insert the character data into the list and maintain order 167 | table.insert(character_list_options, { 168 | ["Name"] = char_name, 169 | ["Trading With"] = trading_with_t, 170 | ["Destination Server"] = server_to_use, 171 | ["Destination Type"] = destination_type, 172 | ["Destination Aetheryte"] = destination_aetheryte, 173 | ["Destination House"] = destination_house, 174 | ["Do Movement"] = do_movement, 175 | ["Return Home"] = return_home, 176 | ["Return Location"] = return_location, 177 | -- Order list 178 | ["_order"] = { 179 | "Name", 180 | "Trading With", 181 | "Destination Server", 182 | "Destination Type", 183 | "Destination Aetheryte", 184 | "Destination House", 185 | "Do Movement", 186 | "Return Home", 187 | "Return Location" 188 | } 189 | }) 190 | end 191 | 192 | return character_list_options 193 | end 194 | 195 | local character_list_options = generate_character_list_options() 196 | 197 | local function write_to_file(filename, data) 198 | local tools_folder = vac_config_folder .. "Tools\\" 199 | EnsureFolderExists(vac_config_folder) 200 | EnsureFolderExists(tools_folder) 201 | local file = io.open(tools_folder .. filename, "w") 202 | 203 | file:write("local character_list_kupobox = {\n") 204 | 205 | for _, char in ipairs(data) do 206 | file:write(" {\n") 207 | local order = char["_order"] 208 | for _, key in ipairs(order) do 209 | local value = char[key] 210 | if type(value) == "string" then 211 | file:write(string.format(" [\"%s\"] = \"%s\",\n", key, value)) 212 | else 213 | file:write(string.format(" [\"%s\"] = %s,\n", key, tostring(value))) 214 | end 215 | end 216 | file:write(" },\n") 217 | end 218 | 219 | file:write("}\n") 220 | file:close() 221 | end 222 | 223 | write_to_file("character_list_kupobox.lua", character_list_options) 224 | 225 | if HasPlugin("YesAlready") then 226 | RestoreYesAlready() 227 | end 228 | -------------------------------------------------------------------------------- /Scripts/Trading Scripts/Kupo Box.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | _ __ ____ 3 | | |/ / | _ \ 4 | | ' / _ _ _ __ ___ | |_) | ___ __ __ 5 | | < | | | || '_ \ / _ \ | _ < / _ \\ \/ / 6 | | . \| |_| || |_) || (_) | | |_) || (_) |> < 7 | |_|\_\\__,_|| .__/ \___/ |____/ \___//_/\_\ 8 | | | 9 | |_| 10 | 11 | #################### 12 | ## Version ## 13 | ## 1.0.0 ## 14 | #################### 15 | 16 | -> 1.0.0: Initial release 17 | 18 | #################################################### 19 | ## Description ## 20 | #################################################### 21 | 22 | https://github.com/WigglyMuffin/SNDScripts 23 | 24 | This script automates a list of characters moving to a location and picking up items from a specified character 25 | It's supposed to be used in pairs with the post moogle script to automate trading a large quantity of items 26 | Almost everything is configurable and lets you change settings on a per character basis, or you can set overrides that apply to every character no matter what the character setting is 27 | 28 | Currently the way it knows when the trades are done is by being traded 1 gil, however this might be changed in the future, or at least made configurable 29 | 30 | #################################################### 31 | ## Requirements ## 32 | #################################################### 33 | 34 | -> AutoRetainer : https://love.puni.sh/ment.json 35 | -> Teleporter : In the default first party dalamud repository 36 | -> Lifestream : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 37 | -> TextAdvance : https://github.com/NightmareXIV/MyDalamudPlugins/raw/main/pluginmaster.json 38 | -> Something Need Doing (Expanded Edition) : https://puni.sh/api/repository/croizat 39 | -> Pandora's Box : https://love.puni.sh/ment.json 40 | -> vnavmesh : https://puni.sh/api/repository/veyn 41 | -> Dropbox : https://puni.sh/api/repository/kawaii 42 | -> Recommended settings in dropbox are 4 frames delay between trades and 1500ms trade open command throttle. (Ctrl + left click to specify exact values). 43 | -> You NEED to enable "Enable auto-accept trades." under the dropbox settings. 44 | 45 | ##################### 46 | ## Settings ## 47 | ##################### 48 | 49 | Edit vac_char_list.lua file for configuring characters, or utilize the local character list below 50 | 51 | These settings will override what you include in the character list, which means if you set a setting here then all characters will use that setting 52 | to use any of the overrides you need to uncomment the line and set it to what you want. uncommenting is just removing the two lines at the start ]] 53 | 54 | -- local trading_with_override = "Smol Meow" -- Name of the character you're trading with, do not include world 55 | -- local destination_server_override = "Sephirot" -- Server characters need to travel to for collecting items 56 | -- local destination_type_override = 0 -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 57 | -- local destination_aetheryte_override = "Aleport" -- Aetheryte that characters need to travel to for collecting items, case insensitive and you can be vague 58 | -- local destination_house_override = 0 -- Options: 0 = FC, 1 = Personal, 2 = Apartment 59 | -- local do_movement_override = true -- Options: true = Paths to chosen character, false = Does nothing and waits for chosen character to come to you 60 | -- local return_home_override = true -- Options: true = Returns home from destination, false = Does nothing and logs out 61 | -- local return_location_override = 0 -- Options: 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 62 | 63 | -- Options: true = invites character you're trading with to party for trading, false = uses distance based proximity check for trading 64 | -- toggling this off is usually the faster but less safe method of trading 65 | local party_invite = true 66 | 67 | -- in case something somehow goes wrong you can set the amount of characters in the list to skip, this goes from the top of the list 68 | -- a good way to know how many chars you actually need to skip is to read the processing echo in chat which lists how many chars it's finished already and which char it's on ]] 69 | local skip_chars = 0 -- number of characters you'd like to skip 70 | 71 | -- Options: true / false 72 | -- If the below options is set to true then it will utilize the external vac_char_list and you need to make sure that is correctly configured 73 | local use_external_character_list = true 74 | 75 | -- This is where you put your character list if you choose to not use the external one 76 | -- If use_external_character_list is set to true then this list is completely skipped 77 | -- This list uses the same options as shown in the overrides above 78 | 79 | local character_list_kupobox = { 80 | { 81 | ["Name"] = "Large Meow@Bismarck", -- the name of the character you're logging in on 82 | ["Trading With"] = "Smol Meow", -- character you're trading with, without world 83 | ["Destination Server"] = "Sephirot", -- server you're going to pick up items on 84 | ["Destination Type"] = 0, -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 85 | ["Destination Aetheryte"] = "Aleport", -- aetheryte to meet at if ["Destination Type"] is set to 0 86 | ["Destination House"] = 0, -- Options: 0 = FC, 1 = Personal, 2 = Apartment // Only active if ["Destination Type"] is set to 1 or 2 87 | ["Do Movement"] = false, -- will move to the character you're trading to, usually this is done by the delivery character 88 | ["Return Home"] = false, -- will just log out if set to false, otherwise will move to home server and to set location configured by ["Return Location"] 89 | ["Return Location"] = 0 -- 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 90 | }, 91 | { 92 | ["Name"] = "Larger Meow@Ravana", -- the name of the character you're logging in on 93 | ["Trading With"] = "Smol Meow", -- character you're trading with, without world 94 | ["Destination Server"] = "Sephirot", -- server you're going to pick up items on 95 | ["Destination Type"] = 0, -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 96 | ["Destination Aetheryte"] = "Aleport", -- aetheryte to meet at if ["Destination Type"] is set to 0 97 | ["Destination House"] = 0, -- Options: 0 = FC, 1 = Personal, 2 = Apartment // Only active if ["Destination Type"] is set to 1 or 2 98 | ["Do Movement"] = false, -- will move to the character you're trading to, usually this is done by the delivery character 99 | ["Return Home"] = false, -- will just log out if set to false, otherwise will move to home server and to set location configured by ["Return Location"] 100 | ["Return Location"] = 0 -- 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 101 | }, 102 | } 103 | 104 | --[[################################# 105 | # DON'T TOUCH ANYTHING BELOW HERE # 106 | # UNLESS YOU KNOW WHAT YOU'RE DOING # 107 | ##################################### 108 | 109 | ################### 110 | # FUNCTION LOADER # 111 | #################]] 112 | 113 | -- Edit char_list.lua file for configuring characters 114 | char_list = "vac_char_list.lua" 115 | 116 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 117 | vac_config_folder = snd_config_folder .. "\\VAC\\" 118 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 119 | LoadFunctions = loadfile(load_functions_file_location)() 120 | LoadFileCheck() 121 | 122 | -- Plugin checker 123 | local required_plugins = { 124 | AutoRetainer = "4.4.4", 125 | TeleporterPlugin = "2.0.2.5", 126 | Lifestream = "2.3.2.8", 127 | SomethingNeedDoing = "1.75", 128 | TextAdvance = "3.2.4.4", 129 | vnavmesh = "0.0.0.54" 130 | } 131 | 132 | if not CheckPlugins(required_plugins) then 133 | return -- Stops script as plugins not available or versions don't match 134 | end 135 | 136 | if HasPlugin("YesAlready") then 137 | PauseYesAlready() 138 | end 139 | 140 | LogInfo("[KupoBox] ##############################") 141 | LogInfo("[KupoBox] Starting script...") 142 | LogInfo("[KupoBox] snd_config_folder: " .. snd_config_folder) 143 | LogInfo("[KupoBox] char_list: " .. char_list) 144 | LogInfo("[KupoBox] SNDConf+Char: " .. snd_config_folder .. "" .. char_list) 145 | LogInfo("[KupoBox] ##############################") 146 | 147 | if use_external_character_list then 148 | local char_data = dofile(snd_config_folder .. char_list) 149 | character_list_kupobox = char_data.character_list_kupobox 150 | end 151 | 152 | --[[########### 153 | # MAIN SCRIPT # 154 | #############]] 155 | 156 | local function ProcessAltCharacters(character_list_kupobox) 157 | for i = 1, #character_list_kupobox do 158 | -- Update alt character name 159 | local alt_char_name = character_list_kupobox[i]["Name"] 160 | 161 | -- this is just to store the boolean for if we're skipping a char or not 162 | local skip = false 163 | 164 | -- check if the character is supposed to be skipped 165 | if i <= skip_chars then 166 | LogInfo("[KupoBox] Skipping char " .. i .. ": " .. alt_char_name ) 167 | skip = true 168 | end 169 | if not skip then 170 | -- apply overrides if they're needed, otherwise set the settings from the character 171 | local trading_with = trading_with_override or character_list_kupobox[i]["Trading With"] 172 | local destination_server = destination_server_override or character_list_kupobox[i]["Destination Server"] 173 | local destination_type = destination_type_override or character_list_kupobox[i]["Destination Type"] 174 | local destination_aetheryte = destination_aetheryte_override or character_list_kupobox[i]["Destination Aetheryte"] 175 | local destination_house = destination_house_override or character_list_kupobox[i]["Destination House"] 176 | local do_movement = do_movement_override or character_list_kupobox[i]["Do Movement"] 177 | local return_home = return_home_override or character_list_kupobox[i]["Return Home"] 178 | local return_location = return_location_override or character_list_kupobox[i]["Return Location"] 179 | 180 | 181 | -- Switch characters if required, looks up current character and compares 182 | if GetCharacterName(true) ~= alt_char_name then 183 | -- checks if return_location options matches 1 which returns player to Limsa 184 | if return_location == 1 then 185 | if not (ZoneCheck("Limsa Lominsa Lower") or ZoneCheck("Limsa Lominsa Upper")) then 186 | Teleporter("Limsa", "tp") 187 | end 188 | end 189 | 190 | RelogCharacter(alt_char_name) 191 | Sleep(7.5) 192 | LoginCheck() 193 | end 194 | 195 | Echo("Picking up items from " .. trading_with .. " on server " .. destination_server) 196 | LogInfo("[KupoBox] Picking up items from " .. trading_with .. " on server " .. destination_server) 197 | 198 | Echo("Processing " .. i .. "/" .. #character_list_kupobox .. ", current character: " .. alt_char_name) 199 | LogInfo("[KupoBox] Processing " .. i .. "/" .. #character_list_kupobox .. ", current character: " .. alt_char_name) 200 | 201 | -- Check if alt character on correct server 202 | if GetCurrentWorld() == World_ID_List[destination_server].ID then 203 | -- If player is on destination_server then do nothing 204 | LogInfo("[KupoBox] Already on the right server to trade: " .. destination_server) 205 | else 206 | -- If player is not on destination_server then go there 207 | LogInfo("[KupoBox] On the wrong server, transferring to: " .. destination_server) 208 | Teleporter(destination_server, "li") 209 | end 210 | 211 | repeat 212 | Sleep(0.1) 213 | until IsPlayerAvailable() and not LifestreamIsBusy() 214 | 215 | -- Alt character destination type, how alt char is travelling to the main 216 | -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 217 | if destination_type == 0 then 218 | local dest_aetheryte_id = FindZoneIDByAetheryte(destination_aetheryte) 219 | 220 | -- If player is not at the destination then tp there 221 | if GetZoneID() ~= dest_aetheryte_id then 222 | Echo("Teleporting to " .. destination_aetheryte .. " to find " .. trading_with) 223 | LogInfo("[KupoBox] Teleporting to " .. destination_aetheryte .. " to find " .. trading_with) 224 | Teleporter(destination_aetheryte, "tp") 225 | else 226 | Echo("Already in the right zone to meet " .. trading_with) 227 | end 228 | end 229 | 230 | -- Requires main added to friend list for access to estate list teleports 231 | -- Keeping it for future stuff 232 | if destination_type > 0 then 233 | Echo("Teleporting to estate to find " .. trading_with) 234 | LogInfo("[KupoBox] Teleporting to estate to find " .. trading_with) 235 | EstateTeleport(trading_with, destination_house) 236 | end 237 | 238 | -- I really don't like the repeat of destination_type checking here, should probably be refactored into stuff above 239 | -- Handle different destination types 240 | -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 241 | if destination_type == 0 or destination_type == 1 then 242 | -- Waits until main char is present 243 | LogInfo("[KupoBox] Waiting for " .. trading_with) 244 | WaitUntilObjectExists(trading_with) 245 | LogInfo("[KupoBox] Found " .. trading_with) 246 | 247 | -- Paths to main char only if you have do_movement set to true 248 | if do_movement then 249 | -- Path to main char 250 | LogInfo("[KupoBox] do_movement is set to true, moving towards " .. trading_with) 251 | PathToObject(trading_with, 3.5) 252 | else 253 | LogInfo("[KupoBox] do_movement is set to false, not moving") 254 | end 255 | 256 | -- Invite main char to party, needs a target 257 | if party_invite then 258 | PartyInvite(trading_with) 259 | LogInfo("[KupoBox] Inviting " .. trading_with .. " to party") 260 | end 261 | 262 | elseif destination_type == 2 then 263 | -- If destination_type is 2, first go to the estate entrance, then to the main character 264 | PathToObject("Entrance") 265 | Target("Entrance") 266 | Interact() 267 | 268 | repeat 269 | Sleep(0.1) 270 | yield("/pcall SelectYesno true 0") 271 | until not IsAddonVisible("SelectYesno") 272 | 273 | -- Waits until main char is present 274 | LogInfo("[KupoBox] Waiting for " .. trading_with) 275 | WaitUntilObjectExists(trading_with) 276 | LogInfo("[KupoBox] Found " .. trading_with) 277 | 278 | -- Paths to main char only if you have do_movement set to true 279 | if do_movement then 280 | -- Path to main char 281 | LogInfo("[KupoBox] do_movement is set to true, moving towards " .. trading_with) 282 | PathToObject(trading_with, 3.5) 283 | else 284 | LogInfo("[KupoBox] do_movement is set to false, not moving") 285 | end 286 | 287 | -- Invite main char to party, needs a target 288 | if party_invite then 289 | PartyInvite(trading_with) 290 | end 291 | end 292 | 293 | -- Wait for the gil transfer to complete 294 | WaitForGilIncrease(1) 295 | 296 | -- Notify when all characters are finished 297 | if i == #character_list_kupobox then 298 | Echo("Finished all " .. #character_list_kupobox .. " characters") 299 | LogInfo("Finished all " .. #character_list_kupobox .. " characters") 300 | end 301 | 302 | -- Disband party once gil trigger has happened 303 | if party_invite then 304 | LogInfo("[KupoBox] Disbanding party") 305 | PartyDisband() 306 | end 307 | 308 | -- Alt character handling to go home 309 | -- [2] return_home options: 0 = no, 1 = yes 310 | -- [3] return_location options: 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 311 | if return_home then 312 | LogInfo("[KupoBox] Returning home") 313 | ReturnHomeWorld() 314 | 315 | -- Limsa stuff 316 | if return_location == 1 then 317 | if not (ZoneCheck("Limsa Lominsa Lower") or ZoneCheck("Limsa Lominsa Upper")) then 318 | LogInfo("[KupoBox] Attempting to go to Limsa") 319 | Teleporter("Limsa", "tp") 320 | end 321 | end 322 | 323 | -- Limsa Retainer Bell Stuff 324 | if return_location == 2 then 325 | LogInfo("[KupoBox] Attempting to go to Limsa retainer bell") 326 | PathToLimsaBell() 327 | end 328 | 329 | -- Nearby Retainer Bell Stuff 330 | if return_location == 3 then 331 | LogInfo("[KupoBox] Attempting to go to nearest retainer bell") 332 | PathToObject("Summoning Bell") 333 | end 334 | 335 | -- FC Entrance stuff 336 | if return_location == 4 then 337 | LogInfo("[KupoBox] Attempting to go to FC Entrance") 338 | Teleporter("Estate Hall (Free Company)", "tp") 339 | PathToObject("Entrance") 340 | end 341 | end 342 | end 343 | skip = false 344 | end 345 | end 346 | 347 | ProcessAltCharacters(character_list_kupobox) 348 | LogInfo("[KupoBox] All characters complete, script finished") 349 | 350 | if HasPlugin("YesAlready") then 351 | RestoreYesAlready() 352 | end 353 | -------------------------------------------------------------------------------- /Scripts/Trading Scripts/Post Moogle CharListGen.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | ############################################################ 4 | ## Post Moogle ## 5 | ## Character List Generator ## 6 | ############################################################ 7 | 8 | 9 | #################### 10 | ## Version ## 11 | ## 1.1.0 ## 12 | #################### 13 | 14 | -> 1.0.0: Initial release 15 | - Basic functionality to generate partner list for Post Moogle 16 | - Support for multiple partner characters 17 | 18 | -> 1.0.1: Comprehensive update for partner-specific functionality 19 | - Adapted core structure from Post Moogle character list generator 20 | - Implemented inverse behavior to complement main Kupo Box generator for Post Moogle: 21 | * gen_char_list now represents partner characters to trade with 22 | * trading_with_list now represents the main trading character(s) 23 | - Added flexibility for various trading scenarios: 24 | * Support for single main trader with multiple partners 25 | * Support for multiple main traders with multiple partners 26 | - Incorporated item list functionality from Post Moogle script 27 | - Enhanced server destination logic: 28 | * Added set_destination_server_to_home_server option for automatic server assignment 29 | - Improved comments and variable names for better readability and maintenance 30 | 31 | -> 1.1.0: Major update to improve flexibility and usability 32 | - Reworked logic to handle various trading scenarios: 33 | * Single delivery character trading with multiple partners 34 | * Multiple delivery characters trading with multiple partners 35 | - Improved handling of gen_char_list and trading_with_list: 36 | * gen_char_list now represents the delivery characters 37 | * trading_with_list now represents the characters to trade with 38 | - Enhanced flexibility in list handling: 39 | * Supports cases where gen_char_list has more entries than trading_with_list 40 | * Handles scenarios where trading_with_list has more entries than gen_char_list 41 | - Implemented flexible entry generation based on the larger of the two lists 42 | - Improved cyclic assignment logic to handle any list size discrepancy 43 | - Maintained item configuration support with always_include list 44 | - Enhanced server destination logic: 45 | * Kept set_destination_server_to_home_server option for automatic server assignment 46 | - Refined code structure for better readability and maintenance 47 | - Updated comments and variable names for clarity 48 | - Ensured compatibility with the main Post Moogle script 49 | 50 | #################################################### 51 | ## Description ## 52 | #################################################### 53 | 54 | The Post Moogle Character List Generator is a versatile Lua script designed to create character configurations for Post Moogle. 55 | 56 | Key Features: 57 | 1. Character-Centric Design: Optimised for setting up characters who will be sending or receiving items through Post Moogle. 58 | 2. Flexible Delivery Scenarios: Supports both one-to-many and many-to-many delivery. 59 | 3. Trading Partner Configuration: Uses gen_char_list for delivery characters and trading_with_list for recipient characters. 60 | 4. Destination Server Logic: Includes options for specifying destination servers for each character. 61 | 5. Item Listing: Incorporates functionality to specify items and quantities for each character to deliver. 62 | 6. Output Compatibility: Generates a Lua table (character_list_postmoogle.lua) that can be directly inserted into vac_char_list or Post Moogle configurations. 63 | 7. Customizable Delivery Parameters: Allows specification of delivery locations, movement options, and return behaviors. 64 | 65 | This script is particularly useful for players managing complex item deliveries. It provides a streamlined way to configure characters for Post Moogle deliveries, ensuring efficient and organised item exchanges. 66 | 67 | #################################################### 68 | ## Required Plugins ## 69 | #################################################### 70 | 71 | -> SomethingNeedDoing 72 | 73 | ##################### 74 | ## Settings ## 75 | ###################]] 76 | 77 | -- Set the characters you're generating a list with, these are the partners to trade with 78 | local gen_char_list = { 79 | "Mrow Mrow@Louisoix", -- Trading partner 1 for main trading character 80 | "Smol Meow@Lich", -- Trading partner 2 for main trading character 81 | "Beeg Meow@Zodiark" -- Trading partner 3 for main trading character 82 | } 83 | 84 | -- Here you can define the main trading character(s). 85 | -- If only one character is listed, it will be used as the main trading partner for all entries in gen_char_list 86 | local trading_with_list = { 87 | "Mrow Mrow@Louisoix", -- Main trading character 88 | -- "Smol Meow@Lich", -- Uncomment to add more main trading characters 89 | -- "Beeg Meow@Zodiark" -- Uncomment to add more main trading characters 90 | } 91 | 92 | -- Here you set the default settings each character will have when generated 93 | 94 | local destination_server = "Zodiark" -- Set this to the server you're meeting the delivery character on 95 | local destination_type = 0 -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 96 | local destination_aetheryte = "Aleport" -- Aetheryte to meet at if ["Destination Type"] is set to 0 97 | local destination_house = 0 -- Options: 0 = FC, 1 = Personal, 2 = Apartment // Only active if ["Destination Type"] is set to 1 or 2 98 | local do_movement = false -- Options: true, false // will move to the character you're trading to, usually this is done by the delivery character 99 | local return_home = false -- Options: true, false // will just log out if set to false, otherwise will move to home server and to set location configured by ["Return Location"] 100 | local return_location = 0 -- Options: 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 101 | 102 | local items = { 103 | -- This is where you configure what items each character is going to be delivering, the format is {"ITEMNAME", AMOUNT} 104 | -- If you want to do it character specific you have to edit the generated character list afterwards 105 | -- It is not case sensitive, however it needs to be the full name so it doesn't accidentally get the wrong item 106 | -- Add or remove as you wish, can even leave it empty just fine 107 | { "Salvaged Ring", 99999 }, 108 | { "Salvaged Bracelet", 99999 }, 109 | { "Salvaged Earring", 99999 }, 110 | { "Salvaged Necklace", 99999 }, 111 | { "Extravagant Salvaged Ring", 99999 }, 112 | { "Extravagant Salvaged Bracelet", 99999 }, 113 | { "Extravagant Salvaged Earring", 99999 }, 114 | { "Extravagant Salvaged Necklace", 99999 } 115 | } 116 | 117 | -- This option if set to true will override destination_server and set it to that chars home server 118 | -- If the list is in order it can be used to make everything faster as the characters do not have to travel anywhere, 119 | -- they just meet the trader on their server at the set location 120 | local set_destination_server_to_home_server = false 121 | 122 | --[[################################# 123 | # DON'T TOUCH ANYTHING BELOW HERE # 124 | # UNLESS YOU KNOW WHAT YOU'RE DOING # 125 | ##################################### 126 | 127 | ################### 128 | # FUNCTION LOADER # 129 | #################]] 130 | 131 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 132 | vac_config_folder = snd_config_folder .. "\\VAC\\" 133 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 134 | LoadFunctions = loadfile(load_functions_file_location) 135 | LoadFunctions() 136 | LoadFileCheck() 137 | 138 | if not CheckPluginsEnabled("SomethingNeedDoing") then 139 | return -- Stops script as plugins not available 140 | end 141 | 142 | if HasPlugin("YesAlready") then 143 | PauseYesAlready() 144 | end 145 | 146 | --[[########### 147 | # MAIN SCRIPT # 148 | #############]] 149 | 150 | local function extract_world_from_name(char_name) 151 | local at_position = string.find(char_name, "@") 152 | if at_position then 153 | return string.sub(char_name, at_position + 1) 154 | end 155 | return nil 156 | end 157 | 158 | local function strip_after_at(input_string) 159 | local result = string.match(input_string, "([^@]+)") 160 | return result 161 | end 162 | 163 | local function generate_character_list_options() 164 | local character_list_options = {} 165 | local num_chars = #gen_char_list 166 | local num_trading_partners = #trading_with_list 167 | 168 | local entries_to_generate = math.max(num_chars, num_trading_partners) 169 | 170 | for i = 1, entries_to_generate do 171 | local trading_with_index = ((i - 1) % num_chars) + 1 172 | local name_index = ((i - 1) % num_trading_partners) + 1 173 | 174 | local char_name = trading_with_list[name_index] 175 | local trading_with_t = strip_after_at(gen_char_list[trading_with_index]) 176 | 177 | local server_to_use = destination_server 178 | 179 | -- If set_destination_server_to_home_server is true, extract the world from the character name 180 | if set_destination_server_to_home_server then 181 | server_to_use = extract_world_from_name(char_name) or destination_server 182 | end 183 | 184 | -- Insert the character data into the list and maintain order 185 | table.insert(character_list_options, { 186 | ["Name"] = char_name, 187 | ["Trading With"] = trading_with_t, 188 | ["Destination Server"] = server_to_use, 189 | ["Destination Type"] = destination_type, 190 | ["Destination Aetheryte"] = destination_aetheryte, 191 | ["Destination House"] = destination_house, 192 | ["Do Movement"] = do_movement, 193 | ["Return Home"] = return_home, 194 | ["Return Location"] = return_location, 195 | ["Items"] = items, 196 | -- Order list 197 | ["_order"] = { 198 | "Name", 199 | "Trading With", 200 | "Destination Server", 201 | "Destination Type", 202 | "Destination Aetheryte", 203 | "Destination House", 204 | "Do Movement", 205 | "Return Home", 206 | "Return Location", 207 | "Items" 208 | } 209 | }) 210 | end 211 | 212 | return character_list_options 213 | end 214 | 215 | local character_list_options = generate_character_list_options() 216 | 217 | local function write_to_file(filename, data) 218 | local tools_folder = vac_config_folder .. "Tools\\" 219 | EnsureFolderExists(vac_config_folder) 220 | EnsureFolderExists(tools_folder) 221 | local file = io.open(tools_folder .. filename, "w") 222 | 223 | file:write("local character_list_postmoogle = {\n") 224 | 225 | for _, char in ipairs(data) do 226 | file:write(" {\n") 227 | local order = char["_order"] 228 | for _, key in ipairs(order) do 229 | local value = char[key] 230 | if type(value) == "string" then 231 | file:write(string.format(" [\"%s\"] = \"%s\",\n", key, value)) 232 | elseif type(value) == "table" then 233 | file:write(string.format(" [\"%s\"] = {\n", key)) 234 | for _, item in ipairs(value) do 235 | file:write(string.format(" { \"%s\", %d },\n", item[1], item[2])) 236 | end 237 | file:write(" },\n") 238 | else 239 | file:write(string.format(" [\"%s\"] = %s,\n", key, tostring(value))) 240 | end 241 | end 242 | file:write(" },\n") 243 | end 244 | 245 | file:write("}\n") 246 | file:close() 247 | end 248 | 249 | write_to_file("character_list_postmoogle.lua", character_list_options) 250 | 251 | if HasPlugin("YesAlready") then 252 | RestoreYesAlready() 253 | end 254 | -------------------------------------------------------------------------------- /Scripts/Trading Scripts/README.md: -------------------------------------------------------------------------------- 1 | # Trading Scripts 2 | 3 | ![Status](https://img.shields.io/badge/status-working-brightgreen) -------------------------------------------------------------------------------- /template.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | ############################################################ 3 | ## SCRIPT ## 4 | ## NAME ## 5 | ############################################################ 6 | https://patorjk.com/software/taag/#p=display&f=Standard&t= (optional to use this in place of above) 7 | 8 | #################### 9 | ## Version ## 10 | ## 1.0.0 ## 11 | #################### 12 | 13 | -> 1.0.0: Initial release 14 | - Changed this 15 | - Changed that 16 | - Not required to create sub lists but it is helpful if there have been a lot of changes, instead you can do just the version and a brief description 17 | -> 1.1.0: Such as this 18 | -> 1.2.0: Changed how this works 19 | -> 1.3.0: Don't forget to change the version above 20 | 21 | #################################################### 22 | ## Description ## 23 | #################################################### 24 | 25 | https://github.com/WigglyMuffin/SNDScripts 26 | 27 | Template of a script 28 | Description of what it does and everything else a user needs to know 29 | 30 | #################################################### 31 | ## Requirements ## 32 | #################################################### 33 | 34 | -> a_plugin : link 35 | -> b_plugin : link 36 | -> c_plugin : link 37 | -> Specific settings a plugin needs or requirements 38 | 39 | Optional plugins: 40 | -> d_plugin : link 41 | 42 | #################################################### 43 | ## Settings ## 44 | ##################################################]] 45 | 46 | -- Put settings and everything a user should configure here 47 | 48 | local a_setting = true -- Options: true = Do this, false = Do that 49 | local b_setting = 100 -- This is how many do this happens 50 | 51 | local conditional_plugin = true -- Example to show optional plugin added to plugin check 52 | 53 | --[[################################################ 54 | ## Script Start ## 55 | ##################################################]] 56 | 57 | snd_config_folder = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\" 58 | vac_config_folder = snd_config_folder .. "\\VAC\\" 59 | load_functions_file_location = os.getenv("appdata") .. "\\XIVLauncher\\pluginConfigs\\SomethingNeedDoing\\vac_functions.lua" 60 | LoadFunctions = loadfile(load_functions_file_location)() 61 | LoadFileCheck() 62 | 63 | -- Plugin checker 64 | local required_plugins = { 65 | a_plugin = "3.0.0", 66 | b_plugin = "2.0.0", 67 | c_plugin = "1.0.0" 68 | } 69 | 70 | -- Add conditional plugins if there are any 71 | if conditional_plugin then 72 | required_plugins.d_plugin = "1.0.0" 73 | end 74 | 75 | if not CheckPlugins(required_plugins) then 76 | return -- Stops script as plugins not available or versions don't match 77 | end 78 | 79 | if HasPlugin("YesAlready") then 80 | PauseYesAlready() 81 | end 82 | 83 | local function Main() 84 | -- Best to do things as functions and call them as they are needed than a top to down checklist of sorts 85 | -- So this could be the main function that calls other parts, check other scripts in our repo for examples of this structure 86 | 87 | -- Best to stay true to a specific coding style too, helps with readability and maintainability 88 | -- We use PascalCase for functions and snake_case for variables etc. 89 | -- Not required if you choose to change things but keep it in mind when using vac_functions and other files 90 | end 91 | 92 | Main() 93 | 94 | if HasPlugin("YesAlready") then 95 | RestoreYesAlready() 96 | end -------------------------------------------------------------------------------- /vac_char_list.lua: -------------------------------------------------------------------------------- 1 | -- Stuff could go here 2 | 3 | -- ########### 4 | -- # CONFIGS # 5 | -- ########### 6 | 7 | -- Usage: First Last@Server 8 | -- This is where your alts are listed 9 | -- used for some simple scripts 10 | local character_list = { 11 | "First Last@Server", 12 | "First Last@Server" 13 | } 14 | 15 | -- this is for use with the Kupo Box item pickup script 16 | local character_list_kupobox = { 17 | { 18 | ["Name"] = "Large Meow@Sephirot", -- The name of the character you're logging in on 19 | ["Trading With"] = "Smol Meow", -- Character you're trading with, without world 20 | ["Destination Server"] = "Sephirot", -- Server you're going to pick up items on 21 | ["Destination Type"] = 0, -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 22 | ["Destination Aetheryte"] = "Aleport", -- Aetheryte to meet at if ["Destination Type"] is set to 0 23 | ["Destination House"] = 0, -- Options: 0 = FC, 1 = Personal, 2 = Apartment // Only active if ["Destination Type"] is set to 1 or 2 24 | ["Do Movement"] = false, -- Options: true, false // will move to the character you're trading to, usually this is done by the delivery character 25 | ["Return Home"] = false, -- Options: true, false // will just log out if set to false, otherwise will move to home server and to set location configured by ["Return Location"] 26 | ["Return Location"] = 0 -- Options: 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 27 | }, 28 | { 29 | ["Name"] = "Larger Meow@Ravana", -- The name of the character you're logging in on 30 | ["Trading With"] = "Smol Meow", -- Character you're trading with, without world 31 | ["Destination Server"] = "Sephirot", -- Server you're going to pick up items on 32 | ["Destination Type"] = 0, -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 33 | ["Destination Aetheryte"] = "Aleport", -- Aetheryte to meet at if ["Destination Type"] is set to 0 34 | ["Destination House"] = 0, -- Options: 0 = FC, 1 = Personal, 2 = Apartment // Only active if ["Destination Type"] is set to 1 or 2 35 | ["Do Movement"] = false, -- Options: true, false // will move to the character you're trading to, usually this is done by the delivery character 36 | ["Return Home"] = false, -- Options: true, false // will just log out if set to false, otherwise will move to home server and to set location configured by ["Return Location"] 37 | ["Return Location"] = 0 -- Options: 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 38 | }, 39 | } 40 | 41 | -- this is for use with the Post Moogle item delivery script 42 | local character_list_postmoogle = { 43 | { 44 | ["Name"] = "Large Meow@Bismarck", -- The name of the character you're using to trade 45 | ["Trading With"] = "Smol Meow", -- Character you're trading with, without world 46 | ["Destination Server"] = "Sephirot", -- Server you're going to meet the recipient 47 | ["Destination Type"] = 0, -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 48 | ["Destination Aetheryte"] = "Aleport", -- Aetheryte to meet at if ["Destination Type"] is set to 0 49 | ["Destination House"] = 0, -- Options: 0 = FC, 1 = Personal, 2 = Apartment // Only active if ["Destination Type"] is set to 1 or 2 50 | ["Do Movement"] = false, -- Will move to the character you're trading to, usually this is done by the delivery character 51 | ["Return Home"] = false, -- Will just log out if set to false, otherwise will move to home server and to set location configured by ["Return Location"]. This is always processed after it no longer has any trades left 52 | ["Return Location"] = 0, -- 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 53 | ["Items"] = { -- This is where you configure what items each character is going to be delivering, the format is {ITEMNAME, AMOUNT} 54 | --{"Copper", 50}, -- It is not case sensitive, however it needs to be the full name so it doesn't accidentally get the wrong item 55 | --{"Gold Ore", 10} 56 | }, 57 | }, 58 | { 59 | ["Name"] = "Larger Meow@Sephirot", -- The name of the character you're using to trade 60 | ["Trading With"] = "Smol Meow", -- Character you're trading with, without world 61 | ["Destination Server"] = "Sephirot", -- Server you're going to meet the recipient 62 | ["Destination Type"] = 0, -- Options: 0 = Aetheryte name, 1 = Estate and meet outside, 2 = Estate and meet inside 63 | ["Destination Aetheryte"] = "Aleport", -- Aetheryte to meet at if ["Destination Type"] is set to 0 64 | ["Destination House"] = 0, -- Options: 0 = FC, 1 = Personal, 2 = Apartment // Only active if ["Destination Type"] is set to 1 or 2 65 | ["Do Movement"] = false, -- Will move to the character you're trading to, usually this is done by the delivery character 66 | ["Return Home"] = false, -- Will just log out if set to false, otherwise will move to home server and to set location configured by ["Return Location"]. This is always processed after it no longer has any trades left 67 | ["Return Location"] = 0, -- 0 = do nothing, 1 = limsa, 2 = limsa bell, 3 = nearby bell, 4 = fc 68 | ["Items"] = { -- This is where you configure what items each character is going to be delivering, the format is {ITEMNAME, AMOUNT} 69 | --{"Copper", 50}, -- It is not case sensitive, however it needs to be the full name so it doesn't accidentally get the wrong item 70 | --{"Gold Ore", 10} 71 | }, 72 | }, 73 | } 74 | 75 | -- ##################################### 76 | -- # DON'T TOUCH ANYTHING BELOW HERE # 77 | -- # UNLESS YOU KNOW WHAT YOU'RE DOING # 78 | -- ##################################### 79 | 80 | return { 81 | character_list = character_list, 82 | character_list_kupobox = character_list_kupobox, 83 | character_list_postmoogle = character_list_postmoogle 84 | } --------------------------------------------------------------------------------