--imports local WIM = WIM; local _G = _G; local string = string; local tostring = tostring; local getn = getn; -- needed for tutorials local MAX_TUTORIAL_VERTICAL_TILE = 30; local MAX_TUTORIAL_IMAGES = 3; local MAX_TUTORIAL_KEYS = 4; local TUTORIALFRAME_TOP_HEIGHT = 80; local TUTORIALFRAME_MIDDLE_HEIGHT = 10; local TUTORIALFRAME_BOTTOM_HEIGHT = 30; local TUTORIALFRAME_WIDTH = 364; --set namespace setfenv(1, WIM); db_defaults.shownTutorials = {}; local Tutorials = CreateModule("Tutorials", true); local function varFriendly(var) var = string.gsub(var, "[^%w_]", "_"); return var; end local theButton; local _FlagTutorial = _G.FlagTutorial; function _G.FlagTutorial(id) local tut = string.match(tostring(id), "^WIM(.+)"); if(tut) then if(tut ~= varFriendly(L["WIM Update Available!"])) then db.shownTutorials[tut] = true; end else _FlagTutorial(id); end end local function setWIMorBlizzard(wim) local alert = _G.TutorialFrameAlertButton; if(wim) then _G.TutorialFrameTop:SetTexture("Interface\\AddOns\\"..WIM.addonTocName.."\\Modules\\Textures\\UI-TUTORIAL-FRAME"); _G.TutorialFrameBottom:SetTexture("Interface\\AddOns\\"..WIM.addonTocName.."\\Modules\\Textures\\UI-TUTORIAL-FRAME"); alert:SetNormalTexture("Interface\\AddOns\\"..WIM.addonTocName.."\\Modules\\Textures\\UI-TUTORIAL-FRAME"); alert:SetHighlightTexture("Interface\\AddOns\\"..WIM.addonTocName.."\\Modules\\Textures\\UI-TUTORIAL-FRAME"); else _G.TutorialFrameTop:SetTexture("Interface\\TutorialFrame\\UI-TUTORIAL-FRAME"); _G.TutorialFrameBottom:SetTexture("Interface\\TutorialFrame\\UI-TUTORIAL-FRAME"); alert:SetNormalTexture("Interface\\TutorialFrame\\UI-TUTORIAL-FRAME"); alert:SetHighlightTexture("Interface\\TutorialFrame\\UI-TUTORIAL-FRAME"); end end local function createChangelogButton() local button = _G.CreateFrame("Button", "WIM_TutorialButtonChangeLog", _G.TutorialFrame, "UIPanelButtonTemplate"); local ok = _G.TutorialFrameOkayButton; button:SetPoint("BOTTOM", 0, 40); button:SetHeight(22); button:SetNormalTexture("DialogButtonNormalTexture"); button:SetPushedTexture("DialogButtonPushedTexture"); button:SetHighlightTexture("DialogButtonHighlightTexture"); button:SetDisabledTexture("DialogButtonDisabledTexture"); _G.WIM_TutorialButtonChangeLogText:SetText(L["View Updates"]); button:SetNormalFontObject("GameFontNormalSmall"); button:SetHighlightFontObject("GameFontNormalSmall"); button:SetDisabledFontObject("GameFontNormalSmall"); button:SetWidth(_G.WIM_TutorialButtonChangeLogText:GetStringWidth()+30) button:Hide(); button:SetScript("OnClick", ShowChangeLog); return button; end local function displayTutorial(title, tutorial) local var = varFriendly(title); if(not db.shownTutorials[var] or L["WIM Update Available!"] == title) then db.shownTutorials[var] = true; theButton = theButton or createChangelogButton(); _G["TUTORIAL_TITLEWIM"..var] = title; _G["TUTORIALWIM"..var] = tutorial; _G.TutorialFrame_NewTutorial("WIM"..var); end end function Tutorials:OnEnable() DisplayTutorial = displayTutorial; end function Tutorials:OnDisable() -- to decrease table lookups, we can just define the function as such. DisplayTutorial = function() end; end local _IsTutorialFlagged = _G.IsTutorialFlagged; function _G.IsTutorialFlagged(id) if(string.match(id, "^[0-9]+$")) then --Blizzard Tutorial, resume... return _IsTutorialFlagged(id); else -- WIM Tutorial return false; end end local ARROW_TYPES = { "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowCurveUpRight", "ArrowCurveUpLeft", "ArrowCurveDownRight", "ArrowCurveDownLeft", "ArrowCurveRightDown", "ArrowCurveRightUp", "ArrowCurveLeftDown", "ArrowCurveLeftUp", } local ARROW_SIZES = { ["ArrowUp"] = {x = 68, y = 89}, ["ArrowDown"] = {x = 68, y = 89}, ["ArrowLeft"] = {x = 89, y = 68}, ["ArrowRight"] = {x = 89, y = 68}, ["ArrowCurveUpRight"] = {x = 66, y = 81}, ["ArrowCurveUpLeft"] = {x = 66, y = 81}, ["ArrowCurveDownRight"] = {x = 66, y = 81}, ["ArrowCurveDownLeft"] = {x = 66, y = 81}, ["ArrowCurveRightDown"] = {x = 82, y = 66}, ["ArrowCurveRightUp"] = {x = 82, y = 66}, ["ArrowCurveLeftDown"] = {x = 82, y = 66}, ["ArrowCurveLeftUp"] = {x = 82, y = 66}, } local MOUSE_SIZE = { x = 76, y = 101} local TUTORIAL_QUEST_ARRAY = { ["HUMAN"] = {questID = 7, displayNPC = 197}, ["DWARF"] = {questID = 7}, ["NIGHTELF"] = {questID = 7}, ["GNOME"] = {questID = 7}, ["DRAENEI"] = {questID = 7}, ["WORGEN"] = {questID = 7}, ["ORC"] = {questID = 7}, ["SCOURGE"] = {questID = 7}, ["TAUREN"] = {questID = 7}, ["TROLL"] = {questID = 7}, ["BLOODELF"] = {questID = 7}, ["GOBLIN"] = {questID = 7}, }; local DISPLAY_DATA = { ["Base"] = { tileHeight = 10, anchorData = {align = "LEFT", xOff = 15, yOff = 30}, textBox = {topLeft_xOff = 33, topLeft_yOff = -75, bottomRight_xOff = -29, bottomRight_yOff = 35}, }, }; local TUTORIAL_HISTORY = {}; -- Tutorial Frame Hook used to implement WIM custom Tutorials. local _TutorialFrame_Update = _G.TutorialFrame_Update; function _G.TutorialFrame_Update(currentTutorial) if(theButton) then theButton:Hide(); end WIM.addToTableUnique(TUTORIAL_HISTORY, currentTutorial); if(string.match(currentTutorial, "^[0-9]+$")) then --Blizzard Tutorial, resume... dPrint("Blizzard Tutorial ID: "..currentTutorial); setWIMorBlizzard(false); _TutorialFrame_Update(currentTutorial); else -- WIM Tutorial dPrint("WIM Tutorial ID: "..currentTutorial); setWIMorBlizzard(true); _G.FlagTutorial(currentTutorial); _G.TutorialFrame.id = currentTutorial; local displayData = DISPLAY_DATA[ currentTutorial ]; if ( not displayData ) then displayData = DISPLAY_DATA["Base"]; end -- setup the frame _G.TutorialFrame_ClearTextures(); if (displayData.anchorData) then local anchorData = displayData.anchorData; _G.TutorialFrame:SetPoint( anchorData.align, _G.UIParent, anchorData.align, anchorData.xOff, anchorData.yOff ); end if (displayData.tileHeight == 0) then _G.TutorialFrameTop:Hide(); _G.TutorialFrameLeft1:Hide(); _G.TutorialFrameRight1:Hide(); _G.TutorialFrameBottom:Hide(); _G.TutorialFrameBackground:Hide(); _G.TutorialFrameCloseButton:Hide(); _G.TutorialFrameOkayButton:Hide(); _G.TutorialFramePrevButton:Hide(); _G.TutorialFrameNextButton:Hide(); _G.TutorialFrame:SetSize(1024, 768); else _G.TutorialFrameTop:Show(); _G.TutorialFrameLeft1:Show(); _G.TutorialFrameRight1:Show(); _G.TutorialFrameBottom:Show(); _G.TutorialFrameBackground:Show(); _G.TutorialFrameCloseButton:Show(); _G.TutorialFrameOkayButton:Show(); _G.TutorialFramePrevButton:Show(); _G.TutorialFrameNextButton:Show(); local anchorParentLeft = _G.TutorialFrameLeft1; local anchorParentRight = _G.TutorialFrameRight1; for i = 2, displayData.tileHeight do local leftTexture = _G["TutorialFrameLeft"..i]; local rightTexture = _G["TutorialFrameRight"..i]; leftTexture:SetPoint("TOPLEFT", anchorParentLeft, "BOTTOMLEFT", 0, 0); rightTexture:SetPoint("TOPRIGHT", anchorParentRight, "BOTTOMRIGHT", 0, 0); leftTexture:Show(); rightTexture:Show(); anchorParentLeft = leftTexture; anchorParentRight = rightTexture; end _G.TutorialFrameBottom:SetPoint("TOPLEFT", anchorParentLeft, "BOTTOMLEFT", 0, 0); _G.TutorialFrameBottom:SetPoint("TOPRIGHT", anchorParentRight, "TOPRIGHT", 0, 0); local height = TUTORIALFRAME_TOP_HEIGHT + (displayData.tileHeight * TUTORIALFRAME_MIDDLE_HEIGHT) + TUTORIALFRAME_BOTTOM_HEIGHT; _G.TutorialFrame:SetSize(TUTORIALFRAME_WIDTH, height); end local _, className = _G.UnitClass("player"); local _, raceName = _G.UnitRace("player"); className = _G.strupper(className); raceName = _G.strupper(raceName); if (displayData.displayNPC) then _G.TutorialNPCModel:SetCreature(TUTORIAL_QUEST_ARRAY[raceName].displayNPC); _G.TutorialNPCModel:Show(); end -- setup the text -- check for class specific first, then race specific, then normal local title = _G["TUTORIAL_TITLE"..currentTutorial.."_"..className]; if ( not title ) then title = _G["TUTORIAL_TITLE"..currentTutorial.."_"..raceName]; if ( not title ) then title = _G["TUTORIAL_TITLE"..currentTutorial]; end end local text = _G["TUTORIAL"..currentTutorial.."_"..className]; if ( not text ) then text = _G["TUTORIAL"..currentTutorial.."_"..raceName]; if ( not text ) then text = _G["TUTORIAL"..currentTutorial]; end end if (displayData.raidwarning) then _G.RaidNotice_AddMessage(_G.RaidWarningFrame, text, _G.ChatTypeInfo["RAID_WARNING"]); return; end if ( title and text) then _G.TutorialFrameTitle:SetText(title); _G.TutorialFrameText:SetText(text); end if ( displayData.textBox) then _G.TutorialFrameTextScrollFrame:SetPoint("TOPLEFT", _G.TutorialFrame, "TOPLEFT", displayData.textBox.topLeft_xOff, displayData.textBox.topLeft_yOff); _G.TutorialFrameTextScrollFrame:SetPoint("BOTTOMRIGHT", _G.TutorialFrame, "BOTTOMRIGHT", displayData.textBox.bottomRight_xOff, displayData.textBox.bottomRight_yOff); end -- setup the callout local callOut = displayData.callOut; if(callOut) then _G.TutorialFrameCallOut:SetSize(callOut.width, callOut.height); _G.TutorialFrameCallOut:SetPoint( callOut.align, callOut.parent, callOut.align, callOut.xOff, callOut.yOff ); _G.TutorialFrameCallOut:Show(); _G.TutorialFrameCallOutPulser:Play(); end -- setup images for i = 1, MAX_TUTORIAL_IMAGES do local imageTexture = _G["TutorialFrameImage"..i]; local imageData = displayData["imageData"..i]; if(imageData and imageTexture) then imageTexture:SetTexture(imageData.file); imageTexture:SetPoint( imageData.align, _G.TutorialFrame, imageData.align, imageData.xOff, imageData.yOff ); if ( imageData.layer ) then imageTexture:SetDrawLayer(imageData.layer); end imageTexture:Show(); elseif( imageTexture ) then imageTexture:ClearAllPoints(); imageTexture:SetTexture(""); imageTexture:Hide(); end end -- setup mouse local mouseData = displayData.mouseData; if(mouseData) then local mouseTexture = _G["TutorialFrameMouse"..mouseData.image]; mouseTexture:SetPoint( mouseData.align, TutorialFrame, mouseData.align, mouseData.xOff, mouseData.yOff ); local scale = 1.0; if ( mouseData.scale ) then scale = mouseData.scale; end mouseTexture:SetWidth( MOUSE_SIZE.x * scale ); mouseTexture:SetHeight( MOUSE_SIZE.y * scale ); if ( mouseData.layer ) then mouseTexture:SetDrawLayer(mouseData.layer); end mouseTexture:Show(); end -- setup keys for i = 1, MAX_TUTORIAL_KEYS do local keyTexture = _G["TutorialFrameKey"..i]; local keyString = _G["TutorialFrameKeyString"..i]; local keyData = displayData["keyData"..i]; if(keyTexture and keyString and keyData) then keyTexture:SetPoint( keyData.align, TutorialFrame, keyData.align, keyData.xOff, keyData.yOff ); keyString:SetText( GetBindingText(GetBindingKey(keyData.command), "KEY_") ); if ( keyData.layer ) then keyTexture:SetDrawLayer(keyData.layer); keyString:SetDrawLayer(keyData.layer); end keyTexture:Show(); keyString:Show(); elseif ( keyTexture ) then keyTexture:ClearAllPoints(); keyTexture:Hide(); keyString:Hide(); end end -- setup arrows for i = 1, getn(ARROW_TYPES) do local arrowData = displayData[ ARROW_TYPES[i] ]; local arrowTexture = _G[ "TutorialFrame"..ARROW_TYPES[i] ]; if ( arrowData and arrowTexture ) then arrowTexture:SetPoint( arrowData.align, TutorialFrame, arrowData.align, arrowData.xOff, arrowData.yOff ); if ( arrowData.layer ) then arrowTexture:SetDrawLayer(arrowData.layer); end local scale = arrowData.scale; if ( not scale ) then scale = 1.0; end arrowTexture:SetWidth( ARROW_SIZES[ARROW_TYPES[i]].x * scale ); arrowTexture:SetHeight( ARROW_SIZES[ARROW_TYPES[i]].y * scale ); arrowTexture:Show(); elseif ( arrowTexture ) then arrowTexture:ClearAllPoints(); arrowTexture:Hide(); end end -- show _G.TutorialFrame:Show(); _G.TutorialFrame_CheckNextPrevButtons(); end end local function getHistoryIndex(id) for i=1, #TUTORIAL_HISTORY do if(TUTORIAL_HISTORY[i] == id) then return i; end end return; end local _GetNextCompleatedTutorial = _G.GetNextCompleatedTutorial; function _G.GetNextCompleatedTutorial(id) if(string.match(id, "^[0-9]+$")) then return _GetNextCompleatedTutorial(id); else local i = getHistoryIndex(id); return i and TUTORIAL_HISTORY[i+1]; end end local _GetPrevCompleatedTutorial = _G.GetPrevCompleatedTutorial; function _G.GetPrevCompleatedTutorial(id) if(string.match(id, "^[0-9]+$")) then return _GetPrevCompleatedTutorial(id); else local i = getHistoryIndex(id); return i and TUTORIAL_HISTORY[i-1]; end end --Global to add tutorial function DisplayTutorial(title, tutorial) -- this function is defined when the module is enabled. end -- this is used to show tutorial even if Tutorials are disabled. DisplayTutorialForce = displayTutorial;