Last active
November 26, 2015 13:52
-
-
Save merlight/e1255719d82e79be3995 to your computer and use it in GitHub Desktop.
MultiCraft modified using ZO_Spinner
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
File : MultiCraft.lua | |
Author: Ayantir | |
Version : 3 | |
]]-- | |
-- MultiCraft totally rewrited by Ayantir | |
local ADDON_NAME = "MultiCraft" | |
-- Inits | |
local sliderValue = 1 | |
local isWorking = false | |
-- Tables | |
local provisioner = {} | |
local enchanting = {} | |
local alchemy = {} | |
local smithing = {} | |
local g_spinner = nil -- will be ZO_Spinner instance | |
local g_lastCraftCount = 1 | |
local selectedCraft = nil -- This will hold a pointer to the currently open crafting station | |
local callDelay = 500 | |
local GENERAL_MODE_CREATION = 1 -- Alchemy, Provisionner | |
local debugEnabled = false | |
local maxCraftable = 1 | |
-- Will output to chat a debug message if MyPrint is enabled | |
function MyPrint(message) | |
if debugEnabled then | |
d(message) | |
end | |
end | |
-- Triggers when EVENT_CRAFT_STARTED and Called at Cleanup | |
local function HideUI() | |
-- Hide XML | |
MultiCraft:SetHidden(true) | |
end | |
local function EnableOrDisableUI() | |
MyPrint(".EnableOrDisableUI()") | |
-- Init | |
local hidden = true | |
local mode = selectedCraft:GetMode() | |
-- Provisioning & Alchemy | |
if selectedCraft == provisioner or | |
selectedCraft == alchemy then | |
if selectedCraft:IsCraftable() then | |
MyPrint(".EnableOrDisableUI->false()") | |
hidden = false | |
end | |
-- Enchanting | |
elseif selectedCraft == enchanting then | |
if (mode == ENCHANTING_MODE_CREATION and selectedCraft:IsCraftable()) or | |
(mode == ENCHANTING_MODE_EXTRACTION and selectedCraft:IsExtractable()) then | |
MyPrint(".EnableOrDisableUI->false()") | |
hidden = false | |
end | |
-- Smithing (Smithing, Wood, Clothing) | |
elseif selectedCraft == smithing then | |
-- there is a game bug where this returns erroneously true in refinement after completing an extract that results in having less | |
-- than 10 items but still having the item selected | |
-- TODO: fix it | |
if (mode == SMITHING_MODE_REFINMENT and selectedCraft:IsExtractable()) or | |
--Aya: Buggy with UI_SHORTCUT_SECONDARY, it will bug the UI -> | |
(mode == SMITHING_MODE_CREATION and selectedCraft:IsCraftable()) or | |
(mode == SMITHING_MODE_CREATION and selectedCraft:IsCraftable()) or | |
(mode == SMITHING_MODE_DECONSTRUCTION and selectedCraft:IsDeconstructable()) then | |
MyPrint(".EnableOrDisableUI->false()") | |
hidden = false | |
end | |
end | |
-- Alchemy ? | |
MyPrint(".EnableOrDisableUI->hidden = " .. tostring(hidden)) | |
-- Hide or Show XML | |
MultiCraft:SetHidden(hidden) | |
end | |
-- This function reset the slider to the correct values (min = 1, max = qty craftable, and maybe the default value) | |
local function ResetSpinner(defaultValue) | |
MyPrint(".ResetSpinner()") | |
-- Can really occurs ? | |
if not selectedCraft then return end | |
-- DisableSlider or show ? | |
EnableOrDisableUI() | |
local numCraftable = 1 | |
-- On which tab are we ? selectedCraft is wrapped by OverrideXXX | |
local mode = selectedCraft:GetMode() | |
-- Get qty craftable | |
-- For Provisionner | |
if selectedCraft == provisioner then | |
if selectedCraft:IsCraftable() then | |
local data = PROVISIONER.recipeTree:GetSelectedData() | |
numCraftable = data.numCreatable | |
else | |
-- Only a try to hide when we cannot do anything, need to be reworked, can occurs if we can do 1 food and 0 drink | |
numCraftable = 0 | |
end | |
-- For Enchanting | |
elseif selectedCraft == enchanting then | |
-- 1st tab, making glyphs | |
if mode == ENCHANTING_MODE_CREATION then | |
if selectedCraft:IsCraftable() then | |
-- We look in craftingInventory (Bagpack+Bank) how much items we got, and we select the min, cause enchanting use 1 rune per glyph | |
for k, v in pairs(ENCHANTING.runeSlots) do | |
if k == 1 then | |
numCraftable = v.craftingInventory.itemCounts[v.itemInstanceId] | |
else | |
numCraftable = zo_min(numCraftable, v.craftingInventory.itemCounts[v.itemInstanceId]) | |
end | |
MyPrint("in for numCraftable = " .. tostring(zo_floor(numCraftable))) | |
end | |
else | |
numCraftable = 0 | |
end | |
-- 2nd tab, deconstruct Glyphs | |
elseif mode == ENCHANTING_MODE_EXTRACTION then | |
if selectedCraft:IsExtractable() then | |
-- We count how many Glyphs we got in craftingInventory (Bagpack+Bank) | |
numCraftable = ENCHANTING.extractionSlot.craftingInventory.itemCounts[ENCHANTING.extractionSlot.itemInstanceId] | |
else | |
numCraftable = 0 | |
end | |
end | |
-- Alchemy | |
elseif selectedCraft == alchemy then | |
if selectedCraft:IsCraftable() then | |
-- Same as enchanting, our Qty will be the min between each solvant and reagents | |
-- Solvant | |
numCraftable = ALCHEMY.solventSlot.craftingInventory.itemCounts[ALCHEMY.solventSlot.itemInstanceId] | |
if numCraftable then | |
-- Reagents | |
for k, data in pairs(ALCHEMY.reagentSlots) do | |
if data:MeetsUsabilityRequirement() then | |
if data.craftingInventory.itemCounts[data.itemInstanceId] ~= nil then | |
numCraftable = zo_min(numCraftable, data.craftingInventory.itemCounts[data.itemInstanceId]) | |
MyPrint("in for numCraftable = " .. tostring(zo_floor(numCraftable))) | |
end | |
end | |
end | |
else | |
-- No solvants in slot | |
numCraftable = 0 | |
end | |
else | |
numCraftable = 0 | |
end | |
-- Smithing (Wood/Smith/Clothing) | |
elseif selectedCraft == smithing then | |
-- 1st tab, refinement | |
if mode == SMITHING_MODE_REFINMENT then | |
-- Count how many Items we got in craftingInventory and divide per stack size needed to refine | |
if selectedCraft:IsExtractable() then | |
numCraftable = SMITHING.refinementPanel.extractionSlot.craftingInventory.itemCounts[SMITHING.refinementPanel.extractionSlot.itemInstanceId] | |
numCraftable = numCraftable / GetRequiredSmithingRefinementStackSize() | |
else | |
numCraftable = 0 | |
end | |
-- 2nd tab, creation | |
elseif mode == SMITHING_MODE_CREATION then | |
if selectedCraft:IsCraftable() then | |
MyPrint("SMITHING Creation") | |
-- Determine qty to craft | |
-- patternIndex is ID of item to do (glove, chest, sword..) | |
-- materialIndex is ID of material to use (galatite, iron, etc) | |
-- materialQuantity is Qty of material to use (10, 12, etc..) | |
-- styleIndex is ID of style to use, qty is always 1 | |
-- traitIndex is ID of trait to use, qty is always 1 | |
local patternIndex, materialIndex, materialQuantity, styleIndex, traitIndex = SMITHING.creationPanel:GetAllCraftingParameters() | |
-- How many material do we got for this item ? | |
local materialCount = GetCurrentSmithingMaterialItemCount(patternIndex, materialIndex) / materialQuantity | |
-- How many stones ? | |
local styleItemCount = GetCurrentSmithingStyleItemCount(styleIndex) | |
-- How many trait stones ? | |
local traitCount = GetCurrentSmithingTraitItemCount(traitIndex) | |
-- Because trait is optional, start with the min of material and style which is always needed | |
numCraftable = zo_min(materialCount, styleItemCount) | |
-- A trait has been selected, 1 is No trait, and if no trait min is already known | |
if traitIndex ~= 1 then | |
-- Protection | |
numCraftable = 1 | |
end | |
else | |
numCraftable = 0 | |
end | |
-- 3rd tab, deconstruction | |
elseif mode == SMITHING_MODE_DECONSTRUCTION then | |
if selectedCraft:IsDeconstructable() then | |
-- Count how many Items we got in craftingInventory | |
numCraftable = SMITHING.deconstructionPanel.extractionSlot.craftingInventory.itemCounts[SMITHING.deconstructionPanel.extractionSlot.itemInstanceId] | |
else | |
numCraftable = 0 | |
end | |
end | |
end | |
-- Protection against divisions | |
numCraftable = zo_floor(numCraftable) | |
if numCraftable > 0 then | |
-- Disable spinner or show ? | |
MyPrint(".ResetSpinner->numCraftable = " .. numCraftable) | |
EnableOrDisableUI() | |
end | |
-- Don't show spinner if Qty = 1 | |
-- MultiCraft is handled by XML | |
if numCraftable <= 1 then | |
MyPrint(".ResetSpinner->Hide spinner") | |
MultiCraft:SetHidden(true) | |
g_spinner:SetMinMax(1, 1) | |
else | |
MyPrint(".ResetSpinner->Show spinner") | |
MultiCraft:SetHidden(false) | |
maxCraftable = numCraftable | |
g_spinner:SetMinMax(1, maxCraftable) | |
g_spinner:SetEnabled(not isWorking) | |
end | |
if defaultValue then | |
g_spinner:SetValue(defaultValue) | |
end | |
end | |
-- Triggers when EVENT_CRAFTING_STATION_INTERACT | |
local function SelectCraftingSkill(eventCode, craftingType) | |
MyPrint("SelectCraftingSkill") | |
-- Provisionner | |
if craftingType == CRAFTING_TYPE_PROVISIONING then | |
selectedCraft = provisioner | |
MyPrint(".SelectCraftingSkill->CRAFTING_TYPE_PROVISIONING") | |
-- Enchanting | |
elseif craftingType == CRAFTING_TYPE_ENCHANTING then | |
selectedCraft = enchanting | |
MyPrint(".SelectCraftingSkill->CRAFTING_TYPE_ENCHANTING") | |
-- Alchemy | |
elseif craftingType == CRAFTING_TYPE_ALCHEMY then | |
selectedCraft = alchemy | |
MyPrint(".SelectCraftingSkill->CRAFTING_TYPE_ALCHEMY") | |
-- Blacksmithing | |
elseif craftingType == CRAFTING_TYPE_BLACKSMITHING then | |
selectedCraft = smithing | |
MyPrint(".SelectCraftingSkill->CRAFTING_TYPE_BLACKSMITHING") | |
-- Clothier | |
elseif craftingType == CRAFTING_TYPE_CLOTHIER then | |
selectedCraft = smithing | |
MyPrint(".SelectCraftingSkill->CRAFTING_TYPE_CLOTHIER") | |
-- Woodworking | |
elseif craftingType == CRAFTING_TYPE_WOODWORKING then | |
selectedCraft = smithing | |
MyPrint(".SelectCraftingSkill->CRAFTING_TYPE_WOODWORKING") | |
end | |
ResetSpinner() | |
-- Prevent UI bug due to fast Esc | |
CALLBACK_MANAGER:FireCallbacks("CraftingAnimationsStopped") | |
end | |
-- Triggers when EVENT_END_CRAFTING_STATION_INTERACT | |
local function Cleanup() | |
-- Hide UI | |
MyPrint(".Cleanup") | |
-- Remove button | |
HideUI() | |
isWorking = false | |
selectedCraft = nil | |
MyPrint(".Cleanup->Cleaned") | |
end | |
-- Executed when EVENT_CRAFT_COMPLETED is triggered, set just before craft has been started | |
local function ContinueWork(workFunc) | |
MyPrint(".ContinueWork") | |
-- Need to do somework ? | |
if sliderValue > 1 and sliderValue <= maxCraftable then | |
-- Let's do another one | |
g_spinner:SetValue(sliderValue - 1) | |
MyPrint("Multicraft will craft : " .. sliderValue) | |
MyPrint("ContinueWork.In.sliderValue " .. sliderValue) | |
-- It will call itself with a delay of XX ms | |
zo_callLater(workFunc, callDelay) | |
else | |
MyPrint(".ContinueWork->finished") | |
-- Work is finished, unregisters itselfs | |
EVENT_MANAGER:UnregisterForEvent(ADDON_NAME, EVENT_CRAFT_COMPLETED) | |
-- Reset spinner to last value, and change work flag | |
isWorking = false | |
ResetSpinner(g_lastCraftCount) | |
end | |
end | |
-- Executed when user start to craft (press the keybind) | |
-- Only for : PROVISIONER:Create(), ENCHANTING:Create(), ALCHEMY:Create(), SMITHING.creationPanel:Create(), SMITHING.deconstructionPanel:Extract(), SMITHING.refinementPanel:Extract() | |
-- When this function is executed, result is always a success, qties and skill have already been verified | |
local function Work(workFunc) | |
MyPrint(".Work") | |
-- selectedCraft is set when entering the craft station, isWorking is for prevent MultiCraft loops, this function is called only at 1st launch | |
if selectedCraft and not isWorking then | |
if MultiCraft:IsHidden() == false then | |
MyPrint("Craft will work 1 item in few ms") | |
MyPrint(".Work:sliderValuee->" .. sliderValue) | |
g_lastCraftCount = sliderValue | |
if sliderValue > 1 and sliderValue <= maxCraftable then | |
-- We're working | |
isWorking = true | |
g_spinner:SetEnabled(false) | |
-- When a craft is completed, execute :ContinueWork to find if we need to continue work | |
EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_CRAFT_COMPLETED, function() ContinueWork(workFunc) end) | |
else | |
MyPrint(".Work:sliderValue->" .. sliderValue) | |
ResetSpinner() | |
-- If user set value to 0, craft will be done and sliderValue set to 1. But if we still can craft more than 1 craft, UI should be displayed again after craft | |
EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_CRAFT_COMPLETED, function() ContinueWork(workFunc) end) | |
end | |
end | |
end | |
end | |
local function OverrideProvisionner() | |
-- Provisioner | |
provisioner.RefreshRecipeList = PROVISIONER.RefreshRecipeList | |
PROVISIONER.RefreshRecipeList = function(...) | |
provisioner.RefreshRecipeList(...) | |
MyPrint("RefreshRecipeList->ResetSpinner") | |
ResetSpinner() | |
end | |
provisioner.SelectNode = PROVISIONER.recipeTree.SelectNode | |
PROVISIONER.recipeTree.SelectNode = function(...) | |
provisioner.SelectNode(...) | |
MyPrint("SelectNode->ResetSpinner") | |
ResetSpinner() | |
end | |
-- Create function | |
provisioner.Create = function() | |
PROVISIONER:Create() | |
end | |
provisioner.GetMode = function() | |
return GENERAL_MODE_CREATION | |
end | |
-- Wrapper to check if an item is craftable | |
provisioner.IsCraftable = function() | |
return PROVISIONER:IsCraftable() | |
end | |
-- wrapper to get the keybind descriptor for the craft button | |
-- Aya: 1.5 dropped KeybindStripDescriptor for PROVISIONER: Replaced by mainKeybindStripDescriptor | |
--provisioner.GetSecondaryKeybindStripDescriptor = function() | |
-- return PROVISIONER.mainKeybindStripDescriptor[1] | |
--end | |
end | |
local function OverrideEnchanting() | |
-- Enchanting | |
-- Tab change | |
enchanting.SetEnchantingMode = ENCHANTING.SetEnchantingMode | |
ENCHANTING.SetEnchantingMode = function(...) | |
enchanting.SetEnchantingMode(...) | |
end | |
-- For polymorphism | |
enchanting.GetMode = function() | |
return ENCHANTING:GetEnchantingMode() | |
end | |
-- Rune slot change | |
enchanting.SetRuneSlotItem = ENCHANTING.SetRuneSlotItem | |
ENCHANTING.SetRuneSlotItem = function(...) | |
enchanting.SetRuneSlotItem(...) | |
-- Reset Slider each time a Runeslot is changed | |
MyPrint("SetRuneSlotItem->ResetSpinner") | |
ResetSpinner() | |
end | |
-- Extraction selection change | |
enchanting.OnSlotChanged = ENCHANTING.OnSlotChanged | |
ENCHANTING.OnSlotChanged = function(...) | |
enchanting.OnSlotChanged(...) | |
-- Reset Slider each time Glyph is changed | |
MyPrint("OnSlotChanged->ResetSpinner") | |
ResetSpinner() | |
end | |
-- Create and extract function | |
enchanting.Create = function() | |
ENCHANTING:Create() | |
end | |
-- wrapper to check if an item is craftable | |
enchanting.IsCraftable = function() | |
return ENCHANTING:IsCraftable() | |
end | |
-- ? | |
enchanting.IsExtractable = enchanting.IsCraftable | |
-- Wrapper to get the keybind descriptor for the craft button | |
--enchanting.GetSecondaryKeybindStripDescriptor = function() | |
-- return ENCHANTING.keybindStripDescriptor[2] | |
--end | |
end | |
local function OverrideAlchemy() | |
-- Alchemy | |
-- Selection Change | |
alchemy.OnSlotChanged = ALCHEMY.OnSlotChanged | |
ALCHEMY.OnSlotChanged = function(...) | |
alchemy.OnSlotChanged(...) | |
-- Reset slider each time a solvant or a plant is changed | |
MyPrint("OnSlotChanged->ResetSpinner") | |
ResetSpinner() | |
end | |
-- Create function | |
alchemy.Create = function() | |
ALCHEMY:Create() | |
end | |
-- For polymorphism | |
alchemy.GetMode = function() | |
return GENERAL_MODE_CREATION | |
end | |
-- Wrapper to check if an item is craftable | |
alchemy.IsCraftable = function() | |
return ALCHEMY:IsCraftable() | |
end | |
end | |
function OverrideSmithing() | |
-- Smithing | |
-- tab change | |
smithing.SetMode = SMITHING.SetMode | |
SMITHING.SetMode = function(...) | |
smithing.SetMode(...) | |
ResetSpinner() | |
end | |
smithing.GetMode = function() | |
return SMITHING.mode | |
end | |
-- Pattern selection in creation | |
smithing.OnSelectedPatternChanged = SMITHING.OnSelectedPatternChanged | |
SMITHING.OnSelectedPatternChanged = function(...) | |
smithing.OnSelectedPatternChanged(...) | |
MyPrint("OnSelectedPatternChanged->ResetSpinner") | |
ResetSpinner() | |
end | |
-- Item selection in deconstruction | |
smithing.OnExtractionSlotChanged = SMITHING.OnExtractionSlotChanged | |
SMITHING.OnExtractionSlotChanged = function(...) | |
smithing.OnExtractionSlotChanged(...) | |
MyPrint("OnExtractionSlotChanged->ResetSpinner") | |
ResetSpinner() | |
end | |
-- Create function | |
smithing.Create = function() | |
SMITHING.creationPanel:Create() | |
end | |
-- Wrapper to check if an item is craftable | |
smithing.IsCraftable = function() | |
return SMITHING.creationPanel:IsCraftable() | |
end | |
-- Deconstruction extract function | |
smithing.Deconstruct = function() | |
SMITHING.deconstructionPanel:Extract() | |
end | |
-- Wrapper to check if an item is deconstructable | |
smithing.IsDeconstructable = function() | |
return SMITHING.deconstructionPanel:IsExtractable() | |
end | |
-- Refinement extract function | |
smithing.Extract = function() | |
SMITHING.refinementPanel:Extract() | |
end | |
-- Wrapper to check if an item is refinable | |
smithing.IsExtractable = function() | |
return SMITHING.refinementPanel:IsExtractable() | |
end | |
end | |
local function onAddonLoaded(_, addonName) | |
-- Protect | |
if addonName == ADDON_NAME then | |
g_spinner = ZO_Spinner:New(MultiCraft:GetNamedChild("Spinner"), 1, 1) | |
g_spinner:RegisterCallback("OnValueChanged", function(value) sliderValue = value end) | |
-- Set up function overrides | |
OverrideProvisionner() | |
OverrideEnchanting() | |
OverrideAlchemy() | |
OverrideSmithing() | |
-- Hook everything up | |
-- Will Hook Real function with MultiCraft ones (MultiCraft function will be executed before real ones) | |
ZO_PreHook(PROVISIONER, 'Create', function() Work(provisioner.Create) end) | |
ZO_PreHook(ENCHANTING, 'Create', function() Work(enchanting.Create) end) | |
ZO_PreHook(ALCHEMY, 'Create', function() Work(alchemy.Create) end) | |
ZO_PreHook(SMITHING.creationPanel, 'Create', function() Work(smithing.Create) end) | |
ZO_PreHook(SMITHING.deconstructionPanel, 'Extract', function() Work(smithing.Deconstruct) end) | |
ZO_PreHook(SMITHING.refinementPanel, 'Extract', function() Work(smithing.Extract) end) | |
-- Register events | |
-- Show UI and set it if needed (slider, #number of crafts) | |
EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_CRAFTING_STATION_INTERACT, SelectCraftingSkill) | |
-- Restore UID when leaving craft station | |
EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_END_CRAFTING_STATION_INTERACT, Cleanup) | |
EVENT_MANAGER:UnregisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED) | |
end | |
end | |
-- Initialize Addon | |
EVENT_MANAGER:RegisterForEvent(ADDON_NAME, EVENT_ADD_ON_LOADED, onAddonLoaded) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<GuiXml> | |
<Controls> | |
<Control name="MultiCraftSpinnerTemplate" mouseEnabled="true" virtual="true" > | |
<Dimensions x="110" y="33" /> | |
<Anchor point="BOTTOM" offsetY="-78" /> | |
<Controls> | |
<Button name="$(parent)Decrease" > | |
<Dimensions x="32" y="32" /> | |
<Anchor point="LEFT" offsetX="-15" /> | |
<Textures normal="EsoUI/Art/Buttons/pointsMinus_up.dds" | |
pressed="EsoUI/Art/Buttons/pointsMinus_down.dds" | |
mouseOver="EsoUI/Art/Buttons/pointsMinus_over.dds" | |
disabled="EsoUI/Art/Buttons/pointsMinus_disabled.dds"/> | |
</Button> | |
<EditBox name="$(parent)Display" inherits="ZO_DefaultEdit" font="ZoFontHeader3" | |
maxInputCharacters="3" textType="NUMERIC_UNSIGNED_INT" > | |
<Anchor point="TOPLEFT" offsetX="40" /> | |
<Anchor point="BOTTOMRIGHT" offsetX="-30" /> | |
</EditBox> | |
<Button name="$(parent)Increase" > | |
<Dimensions x="32" y="32" /> | |
<Anchor point="RIGHT" offsetX="2" /> | |
<Textures normal="EsoUI/Art/Buttons/pointsPlus_up.dds" | |
pressed="EsoUI/Art/Buttons/pointsPlus_down.dds" | |
mouseOver="EsoUI/Art/Buttons/pointsPlus_over.dds" | |
disabled="EsoUI/Art/Buttons/pointsPlus_disabled.dds"/> | |
</Button> | |
</Controls> | |
</Control> | |
<TopLevelControl name="MultiCraft" hidden="true" level="999" > | |
<Anchor point="BOTTOM" /> | |
<Controls> | |
<Control name="$(parent)Spinner" inherits="MultiCraftSpinnerTemplate" > | |
</Control> | |
</Controls> | |
</TopLevelControl> | |
</Controls> | |
</GuiXml> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
LICENSE: http://creativecommons.org/licenses/by-nc-sa/4.0/legalcode