Quantcast

Start of travel module

MilleXIV [08-21-16 - 17:01]
Start of travel module

Hearth buttons aren't working yet, no idea why
Filename
core.lua
locales/enUS.lua
modules/heartstone.lua
modules/load_modules.xml
modules/micromenu.lua
modules/old/heartstone.lua
modules/travel.lua
diff --git a/core.lua b/core.lua
index 79ac44f..4198f5d 100644
--- a/core.lua
+++ b/core.lua
@@ -10,6 +10,7 @@ XIVBar.defaults = {
   profile = {
     general = {
       barPosition = "BOTTOM",
+      barPadding = 3,
     },
     color = {
       barColor = {
@@ -58,7 +59,9 @@ XIVBar.defaults = {
 XIVBar.constants = {
   mediaPath = "Interface\\AddOns\\"..AddOnName.."\\media\\",
   playerName = UnitName("player"),
-  playerClass = select(2, UnitClass("player"))
+  playerClass = select(2, UnitClass("player")),
+  playerLevel = UnitLevel("player"),
+  popupPadding = 3
 }

 XIVBar.LSM = LibStub('LibSharedMedia-3.0');
@@ -219,7 +222,7 @@ function XIVBar:CreateMainBar()
 end

 function XIVBar:GetHeight()
-  return (self.db.profile.text.fontSize * 2) + 3
+  return (self.db.profile.text.fontSize * 2) + self.db.profile.general.barPadding
 end

 function XIVBar:Refresh()
@@ -264,6 +267,14 @@ function XIVBar:RGBAToHex(r, g, b, a)
   return string.format("%02x%02x%02x%02x", r*255, g*255, b*255, a*255)
 end

+function XIVBar:HexToRGBA(hex)
+  local rhex, ghex, bhex, ahex = string.sub(hex, 1, 2), string.sub(hex, 3, 4), string.sub(hex, 5, 6), string.sub(hex, 7, 8)
+  if not (rhex and ghex and bhex and ahex) then
+    return 0, 0, 0, 0
+  end
+  return (tonumber(rhex, 16) / 255), (tonumber(ghex, 16) / 255), (tonumber(bhex, 16) / 255), (tonumber(ahex, 16) / 255)
+end
+


 function XIVBar:GetGeneralOptions()
@@ -300,6 +311,16 @@ function XIVBar:GetGeneralOptions()
         get = function() return XIVBar:GetColor('barColor') end,
         disabled = function() return self.db.profile.color.useCC end
       },
+      barPadding = {
+        name = L['Bar Padding'],
+        type = 'range',
+        order = 4,
+        min = 0,
+        max = 10,
+        step = 1,
+        get = function() return self.db.profile.general.barPadding; end,
+        set = function(info, val) self.db.profile.general.barPadding = val; self:Refresh(); end
+      }
     }
   }
 end
diff --git a/locales/enUS.lua b/locales/enUS.lua
index 3602156..96eb596 100644
--- a/locales/enUS.lua
+++ b/locales/enUS.lua
@@ -15,6 +15,7 @@ L['Top'] = true;
 L['Bottom'] = true;
 L['Bar Color'] = true;
 L['Use Class Colors for Bar'] = true;
+L['Bar Padding'] = true;

 -- Media
 L['Font'] = true;
@@ -60,3 +61,5 @@ L['Local Time'] = true;
 L['Realm Time'] = true;
 L['Open Calendar'] = true;
 L['Open Clock'] = true;
+
+L['Travel'] = true;
diff --git a/modules/heartstone.lua b/modules/heartstone.lua
deleted file mode 100644
index 322ca4b..0000000
--- a/modules/heartstone.lua
+++ /dev/null
@@ -1,251 +0,0 @@
-local addon, ns = ...
-local cfg = ns.cfg
-local unpack = unpack
---------------------------------------------------------------
-if not cfg.heartstone.show then return end
-
-local garrOnHover = false
-local hsOnHover = false
-
-local teleportFrame = CreateFrame("Frame",nil, cfg.SXframe)
-teleportFrame:SetPoint("RIGHT",-4,0)
-teleportFrame:SetSize(16, 16)
----------------------------------------------------------------------
-local HSFrame = CreateFrame("BUTTON","hsButton", teleportFrame, "SecureActionButtonTemplate")
-HSFrame:SetPoint("RIGHT")
-HSFrame:SetSize(16, 16)
-HSFrame:EnableMouse(true)
-HSFrame:RegisterForClicks("AnyUp")
-HSFrame:SetAttribute("type", "macro")
-
-local HSText = HSFrame:CreateFontString(nil, "OVERLAY")
-HSText:SetFont(cfg.text.font, cfg.text.normalFontSize)
-HSText:SetPoint("RIGHT")
-HSText:SetTextColor(unpack(cfg.color.normal))
-
-local HSIcon = HSFrame:CreateTexture(nil,"OVERLAY",nil,7)
-HSIcon:SetSize(16, 16)
-HSIcon:SetPoint("RIGHT", HSText,"LEFT",-2,0)
-HSIcon:SetTexture(cfg.mediaFolder.."datatexts\\hearth")
-HSIcon:SetVertexColor(unpack(cfg.color.normal))
-
-HSFrame:SetScript("OnEnter", function()
-	if InCombatLockdown() then return end
-	HSIcon:SetVertexColor(unpack(cfg.color.hover))
-	if not cfg.heartstone.showTooltip then return end
-	local startTime, duration = GetItemCooldown(6948)
-	if startTime ~= 0 then
-		local CDremaining = (startTime+duration)-GetTime()
-		GameTooltip:SetOwner(teleportFrame, cfg.tooltipPos)
-		GameTooltip:AddDoubleLine("Cooldown",SecondsToTime(CDremaining),1,1,0,1,1,1)
-		GameTooltip:Show()
-	end
-	hsOnHover = true
-end)
-
-HSFrame:SetScript("OnLeave", function()
-	hsOnHover = false
-	if IsUsableItem(6948) and GetItemCooldown(6948) == 0 or IsPlayerSpell(556) and GetSpellCooldown(556) == 0 then
-		HSIcon:SetVertexColor(unpack(cfg.color.normal))
-	else
-		HSIcon:SetVertexColor(unpack(cfg.color.inactive))
-	end
-end)
-
--- Change the button action before the click reaches it:
-function HSFrame:ChangeAction(action)
-     if InCombatLockdown() then return end -- can't change attributes in combat
-     self:SetAttribute("macrotext", action)
-end
-
-HSFrame:SetScript("PreClick", function(self)
-     if InCombatLockdown() then return end -- can't change attributes in combat
-
-     -- Innkeeper's Daughter
-     if PlayerHasToy(64488) and GetItemCooldown(64488) == 0 then
-          local itemName, itemLink, _, _, _, _, _, _, _, itemIcon = GetItemInfo(64488)
-          return self:ChangeAction("/use " .. itemName)
-
-     -- Hearthstone
-     elseif IsUsableItem(6948) and GetItemCooldown(6948) == 0 then
-          local itemName, itemLink, _, _, _, _, _, _, _, itemIcon = GetItemInfo(6948)
-          return self:ChangeAction("/use " .. itemName)
-
-     -- Astral Recall
-     elseif IsPlayerSpell(556) and GetSpellCooldown(556) == 0 then
-          local spellName, _, spellIcon = GetSpellInfo(556)
-          return self:ChangeAction("/cast " .. spellName)
-     end
-
-     local playerLevel = UnitLevel("player")
-
-     if playerLevel > 70 and IsUsableItem(44315) and GetItemCooldown(44315) == 0 then
-          return self:SetAttribute("macrotext", "/use Scroll of Recall III")
-
-     elseif playerLevel > 40 and IsUsableItem(44314) and GetItemCooldown(44314) == 0 then
-          return self:SetAttribute("macrotext", "/use Scroll of Recall II")
-
-     elseif playerLevel <= 39 and IsUsableItem(37118) and GetItemCooldown(37118) == 0 then
-          return self:SetAttribute("macrotext", "/use Scroll of Recall")
-
-     end
-end)
----------------------------------------------------------------------
-local garrisonFrame = CreateFrame("BUTTON","garrisonButton", teleportFrame, "SecureActionButtonTemplate")
-garrisonFrame:SetPoint("LEFT")
-garrisonFrame:SetSize(16, 16)
-garrisonFrame:EnableMouse(true)
-garrisonFrame:RegisterForClicks("AnyUp")
-garrisonFrame:SetAttribute("*type1", "macro")
-
--- Change the button action before the click reaches it:
-function garrisonFrame:ChangeAction(action)
-     if InCombatLockdown() then return end -- can't change attributes in combat
-     self:SetAttribute("macrotext", action)
-end
-
-garrisonFrame:SetScript("PreClick", function(self)
-     if InCombatLockdown() then return end -- can't change attributes in combat
-
-	 if IsShiftKeyDown() then
-		if IsUsableItem(128353) and GetItemCooldown(128353) == 0 then
-			local itemName, itemLink, _, _, _, _, _, _, _, itemIcon = GetItemInfo(128353)
-			return self:ChangeAction("/use " .. itemName)
-		end
-	else
-		if IsUsableItem(110560) and GetItemCooldown(110560) == 0 then
-			local itemName, itemLink, _, _, _, _, _, _, _, itemIcon = GetItemInfo(110560)
-			return self:ChangeAction("/use " .. itemName)
-		end
-	end
-end)
-
-
-local garrisonIcon = garrisonFrame:CreateTexture(nil,"OVERLAY",nil,7)
-garrisonIcon:SetSize(16, 16)
-garrisonIcon:SetPoint("LEFT")
-garrisonIcon:SetTexture(cfg.mediaFolder.."datatexts\\garr")
-garrisonIcon:SetVertexColor(unpack(cfg.color.normal))
-
-local garrisonText = garrisonFrame:CreateFontString(nil, "OVERLAY")
-garrisonText:SetFont(cfg.text.font, cfg.text.normalFontSize)
-garrisonText:SetPoint("LEFT", garrisonIcon,"RIGHT",2,0)
-garrisonText:SetText("GARRISON")
-garrisonText:SetTextColor(unpack(cfg.color.normal))
-
-garrisonFrame:SetScript("OnEnter", function()
-	if InCombatLockdown() then return end
-	local startTime, duration = GetItemCooldown(110560)
-	if startTime ~= 0 then
-		local CDremaining = (startTime+duration)-GetTime()
-		GameTooltip:SetOwner(teleportFrame, cfg.tooltipPos)
-		GameTooltip:AddDoubleLine("Cooldown",SecondsToTime(CDremaining),1,1,0,1,1,1)
-		GameTooltip:Show()
-	end
-	garrisonIcon:SetVertexColor(unpack(cfg.color.hover))
-	garrOnHover = true
-end)
-
-garrisonFrame:SetScript("OnLeave", function()
-	garrOnHover = false
-	if IsUsableItem(110560) and GetItemCooldown(110560) == 0 then
-		garrisonIcon:SetVertexColor(unpack(cfg.color.normal))
-	else
-		garrisonIcon:SetVertexColor(unpack(cfg.color.inactive))
-	end
-	GameTooltip:Hide()
-end)
-
-local function hsHover()
-local startTime, duration = GetItemCooldown(6948)
-	if startTime ~= 0 then
-		local CDremaining = (startTime+duration)-GetTime()
-		GameTooltip:SetOwner(teleportFrame, cfg.tooltipPos)
-		GameTooltip:AddDoubleLine("Cooldown",SecondsToTime(CDremaining),1,1,0,1,1,1)
-		GameTooltip:Show()
-	end
-	HSIcon:SetVertexColor(unpack(cfg.color.hover))
-end
-
-local function garrHover()
-local startTime, duration = GetItemCooldown(110560)
-	if startTime ~= 0 then
-		local CDremaining = (startTime+duration)-GetTime()
-		GameTooltip:SetOwner(teleportFrame, cfg.tooltipPos)
-		GameTooltip:AddDoubleLine("Cooldown",SecondsToTime(CDremaining),1,1,0,1,1,1)
-		GameTooltip:Show()
-	end
-	garrisonIcon:SetVertexColor(unpack(cfg.color.hover))
-end
-
-local function updateTeleportText()
-local playerLevel = UnitLevel("player")
-	if PlayerHasToy(64488) and GetItemCooldown(64488) == 0
-	or IsUsableItem(6948) and GetItemCooldown(6948) == 0
-	or IsPlayerSpell(556) and GetSpellCooldown(556) == 0
-    or playerLevel > 70 and IsUsableItem(44315) and GetItemCooldown(44315) == 0
-    or playerLevel > 40 and IsUsableItem(44314) and GetItemCooldown(44314) == 0
-    or playerLevel <= 39 and IsUsableItem(37118) and GetItemCooldown(37118) == 0
-	then
-		HSIcon:SetVertexColor(unpack(cfg.color.normal))
-		HSText:SetTextColor(unpack(cfg.color.normal))
-	else
-		HSIcon:SetVertexColor(unpack(cfg.color.inactive))
-		HSText:SetTextColor(unpack(cfg.color.inactive))
-	end
-
-	if IsUsableItem(110560) and GetItemCooldown(110560) == 0 then
-		garrisonIcon:SetVertexColor(unpack(cfg.color.normal))
-		garrisonText:SetTextColor(unpack(cfg.color.normal))
-	else
-		garrisonIcon:SetVertexColor(unpack(cfg.color.inactive))
-		garrisonText:SetTextColor(unpack(cfg.color.inactive))
-	end
-end
-
-local elapsed = 0
-teleportFrame:SetScript('OnUpdate', function(self, e)
-	elapsed = elapsed + e
-	if elapsed >= 1 then
-		updateTeleportText()
-		if garrOnHover then garrHover() end
-		if hsOnHover then hsHover() end
-		elapsed = 0
-	end
-end)
-
-local eventframe = CreateFrame("Frame")
-eventframe:RegisterEvent("PLAYER_ENTERING_WORLD")
-eventframe:RegisterEvent("BAG_UPDATE")
-eventframe:RegisterEvent("HEARTHSTONE_BOUND")
-eventframe:RegisterEvent("MODIFIER_STATE_CHANGED")
-
-eventframe:SetScript("OnEvent", function(this, event, arg1, arg2, arg3, arg4, ...)
-if InCombatLockdown() then return end
-
-HSText:SetText(strupper(GetBindLocation()))
-HSFrame:SetSize(HSText:GetStringWidth()+16, 16)
-
-
-if IsUsableItem(110560) then
-	garrisonFrame:Show()
-else
-	garrisonFrame:Hide()
-end
-
-if event == "MODIFIER_STATE_CHANGED" then
-	if arg1 == "LSHIFT" or arg1 == "RSHIFT" then
-		if arg2 == 1 then
-			if IsUsableItem(128353) then
-				garrisonText:SetText("SHIPYARD")
-				garrisonIcon:SetTexture(cfg.mediaFolder.."datatexts\\shipcomp")
-			end
-		elseif arg2 == 0 then
-			garrisonText:SetText("GARRISON")
-			garrisonIcon:SetTexture(cfg.mediaFolder.."datatexts\\garr")
-		end
-	end
-end
-	garrisonFrame:SetSize(garrisonText:GetStringWidth()+16, 16)
-	teleportFrame:SetSize(HSFrame:GetWidth()+garrisonFrame:GetWidth()+8, 16)
-end)
diff --git a/modules/load_modules.xml b/modules/load_modules.xml
index ea97f09..f656a98 100644
--- a/modules/load_modules.xml
+++ b/modules/load_modules.xml
@@ -3,4 +3,5 @@
   <Script file="micromenu.lua" />
   <Script file="clock.lua" />
   <Script file="armor.lua" />
+  <Script file="travel.lua" />
 </Ui>
diff --git a/modules/micromenu.lua b/modules/micromenu.lua
index c9a0ced..b34e892 100644
--- a/modules/micromenu.lua
+++ b/modules/micromenu.lua
@@ -101,7 +101,7 @@ function MenuModule:Refresh()
       totalWidth = totalWidth + frame:GetWidth() + xb.db.profile.modules.microMenu.iconSpacing
     end
   end
-  self.microMenuFrame:SetPoint("LEFT")
+  self.microMenuFrame:SetPoint("LEFT", xb.db.profile.general.barPadding, 0)
   self.microMenuFrame:SetSize(totalWidth, xb:GetHeight())

   for name, frame in pairs(self.text) do
@@ -260,12 +260,13 @@ function MenuModule:SocialHover(hoverFunc)
     if totalBNOnlineFriends then

       for i = 1, BNGetNumFriends() do
-        local _, battleName, battleTag, _, charName, _, gameClient, isOnline, _, isAfk, isDnd, _, note = BNGetFriendInfo(i)
+        local _, battleName, battleTag, _, charName, gameAccount, gameClient, isOnline, _, isAfk, isDnd, _, note = BNGetFriendInfo(i)
         if isOnline then
           if not battleTag then
             battleTag = '['..L['No Tag']..']'
           end

+          local _, _, _, realmName, _ = BNGetGameAccountInfo(gameAccount)
           local status = L['Online']
           local statusIcon = FRIENDS_TEXTURE_ONLINE
           local socialIcon = MenuModule.socialIcons[gameClient].icon
@@ -281,7 +282,7 @@ function MenuModule:SocialHover(hoverFunc)
           end

           if gameClient == BNET_CLIENT_WOW then
-            charName = "(|cffecd672"..charName.."|r)"
+            charName = "(|cffecd672"..charName.."-"..realmName.."|r)"
           else
             charName = ''
           end
diff --git a/modules/old/heartstone.lua b/modules/old/heartstone.lua
new file mode 100644
index 0000000..322ca4b
--- /dev/null
+++ b/modules/old/heartstone.lua
@@ -0,0 +1,251 @@
+local addon, ns = ...
+local cfg = ns.cfg
+local unpack = unpack
+--------------------------------------------------------------
+if not cfg.heartstone.show then return end
+
+local garrOnHover = false
+local hsOnHover = false
+
+local teleportFrame = CreateFrame("Frame",nil, cfg.SXframe)
+teleportFrame:SetPoint("RIGHT",-4,0)
+teleportFrame:SetSize(16, 16)
+---------------------------------------------------------------------
+local HSFrame = CreateFrame("BUTTON","hsButton", teleportFrame, "SecureActionButtonTemplate")
+HSFrame:SetPoint("RIGHT")
+HSFrame:SetSize(16, 16)
+HSFrame:EnableMouse(true)
+HSFrame:RegisterForClicks("AnyUp")
+HSFrame:SetAttribute("type", "macro")
+
+local HSText = HSFrame:CreateFontString(nil, "OVERLAY")
+HSText:SetFont(cfg.text.font, cfg.text.normalFontSize)
+HSText:SetPoint("RIGHT")
+HSText:SetTextColor(unpack(cfg.color.normal))
+
+local HSIcon = HSFrame:CreateTexture(nil,"OVERLAY",nil,7)
+HSIcon:SetSize(16, 16)
+HSIcon:SetPoint("RIGHT", HSText,"LEFT",-2,0)
+HSIcon:SetTexture(cfg.mediaFolder.."datatexts\\hearth")
+HSIcon:SetVertexColor(unpack(cfg.color.normal))
+
+HSFrame:SetScript("OnEnter", function()
+	if InCombatLockdown() then return end
+	HSIcon:SetVertexColor(unpack(cfg.color.hover))
+	if not cfg.heartstone.showTooltip then return end
+	local startTime, duration = GetItemCooldown(6948)
+	if startTime ~= 0 then
+		local CDremaining = (startTime+duration)-GetTime()
+		GameTooltip:SetOwner(teleportFrame, cfg.tooltipPos)
+		GameTooltip:AddDoubleLine("Cooldown",SecondsToTime(CDremaining),1,1,0,1,1,1)
+		GameTooltip:Show()
+	end
+	hsOnHover = true
+end)
+
+HSFrame:SetScript("OnLeave", function()
+	hsOnHover = false
+	if IsUsableItem(6948) and GetItemCooldown(6948) == 0 or IsPlayerSpell(556) and GetSpellCooldown(556) == 0 then
+		HSIcon:SetVertexColor(unpack(cfg.color.normal))
+	else
+		HSIcon:SetVertexColor(unpack(cfg.color.inactive))
+	end
+end)
+
+-- Change the button action before the click reaches it:
+function HSFrame:ChangeAction(action)
+     if InCombatLockdown() then return end -- can't change attributes in combat
+     self:SetAttribute("macrotext", action)
+end
+
+HSFrame:SetScript("PreClick", function(self)
+     if InCombatLockdown() then return end -- can't change attributes in combat
+
+     -- Innkeeper's Daughter
+     if PlayerHasToy(64488) and GetItemCooldown(64488) == 0 then
+          local itemName, itemLink, _, _, _, _, _, _, _, itemIcon = GetItemInfo(64488)
+          return self:ChangeAction("/use " .. itemName)
+
+     -- Hearthstone
+     elseif IsUsableItem(6948) and GetItemCooldown(6948) == 0 then
+          local itemName, itemLink, _, _, _, _, _, _, _, itemIcon = GetItemInfo(6948)
+          return self:ChangeAction("/use " .. itemName)
+
+     -- Astral Recall
+     elseif IsPlayerSpell(556) and GetSpellCooldown(556) == 0 then
+          local spellName, _, spellIcon = GetSpellInfo(556)
+          return self:ChangeAction("/cast " .. spellName)
+     end
+
+     local playerLevel = UnitLevel("player")
+
+     if playerLevel > 70 and IsUsableItem(44315) and GetItemCooldown(44315) == 0 then
+          return self:SetAttribute("macrotext", "/use Scroll of Recall III")
+
+     elseif playerLevel > 40 and IsUsableItem(44314) and GetItemCooldown(44314) == 0 then
+          return self:SetAttribute("macrotext", "/use Scroll of Recall II")
+
+     elseif playerLevel <= 39 and IsUsableItem(37118) and GetItemCooldown(37118) == 0 then
+          return self:SetAttribute("macrotext", "/use Scroll of Recall")
+
+     end
+end)
+---------------------------------------------------------------------
+local garrisonFrame = CreateFrame("BUTTON","garrisonButton", teleportFrame, "SecureActionButtonTemplate")
+garrisonFrame:SetPoint("LEFT")
+garrisonFrame:SetSize(16, 16)
+garrisonFrame:EnableMouse(true)
+garrisonFrame:RegisterForClicks("AnyUp")
+garrisonFrame:SetAttribute("*type1", "macro")
+
+-- Change the button action before the click reaches it:
+function garrisonFrame:ChangeAction(action)
+     if InCombatLockdown() then return end -- can't change attributes in combat
+     self:SetAttribute("macrotext", action)
+end
+
+garrisonFrame:SetScript("PreClick", function(self)
+     if InCombatLockdown() then return end -- can't change attributes in combat
+
+	 if IsShiftKeyDown() then
+		if IsUsableItem(128353) and GetItemCooldown(128353) == 0 then
+			local itemName, itemLink, _, _, _, _, _, _, _, itemIcon = GetItemInfo(128353)
+			return self:ChangeAction("/use " .. itemName)
+		end
+	else
+		if IsUsableItem(110560) and GetItemCooldown(110560) == 0 then
+			local itemName, itemLink, _, _, _, _, _, _, _, itemIcon = GetItemInfo(110560)
+			return self:ChangeAction("/use " .. itemName)
+		end
+	end
+end)
+
+
+local garrisonIcon = garrisonFrame:CreateTexture(nil,"OVERLAY",nil,7)
+garrisonIcon:SetSize(16, 16)
+garrisonIcon:SetPoint("LEFT")
+garrisonIcon:SetTexture(cfg.mediaFolder.."datatexts\\garr")
+garrisonIcon:SetVertexColor(unpack(cfg.color.normal))
+
+local garrisonText = garrisonFrame:CreateFontString(nil, "OVERLAY")
+garrisonText:SetFont(cfg.text.font, cfg.text.normalFontSize)
+garrisonText:SetPoint("LEFT", garrisonIcon,"RIGHT",2,0)
+garrisonText:SetText("GARRISON")
+garrisonText:SetTextColor(unpack(cfg.color.normal))
+
+garrisonFrame:SetScript("OnEnter", function()
+	if InCombatLockdown() then return end
+	local startTime, duration = GetItemCooldown(110560)
+	if startTime ~= 0 then
+		local CDremaining = (startTime+duration)-GetTime()
+		GameTooltip:SetOwner(teleportFrame, cfg.tooltipPos)
+		GameTooltip:AddDoubleLine("Cooldown",SecondsToTime(CDremaining),1,1,0,1,1,1)
+		GameTooltip:Show()
+	end
+	garrisonIcon:SetVertexColor(unpack(cfg.color.hover))
+	garrOnHover = true
+end)
+
+garrisonFrame:SetScript("OnLeave", function()
+	garrOnHover = false
+	if IsUsableItem(110560) and GetItemCooldown(110560) == 0 then
+		garrisonIcon:SetVertexColor(unpack(cfg.color.normal))
+	else
+		garrisonIcon:SetVertexColor(unpack(cfg.color.inactive))
+	end
+	GameTooltip:Hide()
+end)
+
+local function hsHover()
+local startTime, duration = GetItemCooldown(6948)
+	if startTime ~= 0 then
+		local CDremaining = (startTime+duration)-GetTime()
+		GameTooltip:SetOwner(teleportFrame, cfg.tooltipPos)
+		GameTooltip:AddDoubleLine("Cooldown",SecondsToTime(CDremaining),1,1,0,1,1,1)
+		GameTooltip:Show()
+	end
+	HSIcon:SetVertexColor(unpack(cfg.color.hover))
+end
+
+local function garrHover()
+local startTime, duration = GetItemCooldown(110560)
+	if startTime ~= 0 then
+		local CDremaining = (startTime+duration)-GetTime()
+		GameTooltip:SetOwner(teleportFrame, cfg.tooltipPos)
+		GameTooltip:AddDoubleLine("Cooldown",SecondsToTime(CDremaining),1,1,0,1,1,1)
+		GameTooltip:Show()
+	end
+	garrisonIcon:SetVertexColor(unpack(cfg.color.hover))
+end
+
+local function updateTeleportText()
+local playerLevel = UnitLevel("player")
+	if PlayerHasToy(64488) and GetItemCooldown(64488) == 0
+	or IsUsableItem(6948) and GetItemCooldown(6948) == 0
+	or IsPlayerSpell(556) and GetSpellCooldown(556) == 0
+    or playerLevel > 70 and IsUsableItem(44315) and GetItemCooldown(44315) == 0
+    or playerLevel > 40 and IsUsableItem(44314) and GetItemCooldown(44314) == 0
+    or playerLevel <= 39 and IsUsableItem(37118) and GetItemCooldown(37118) == 0
+	then
+		HSIcon:SetVertexColor(unpack(cfg.color.normal))
+		HSText:SetTextColor(unpack(cfg.color.normal))
+	else
+		HSIcon:SetVertexColor(unpack(cfg.color.inactive))
+		HSText:SetTextColor(unpack(cfg.color.inactive))
+	end
+
+	if IsUsableItem(110560) and GetItemCooldown(110560) == 0 then
+		garrisonIcon:SetVertexColor(unpack(cfg.color.normal))
+		garrisonText:SetTextColor(unpack(cfg.color.normal))
+	else
+		garrisonIcon:SetVertexColor(unpack(cfg.color.inactive))
+		garrisonText:SetTextColor(unpack(cfg.color.inactive))
+	end
+end
+
+local elapsed = 0
+teleportFrame:SetScript('OnUpdate', function(self, e)
+	elapsed = elapsed + e
+	if elapsed >= 1 then
+		updateTeleportText()
+		if garrOnHover then garrHover() end
+		if hsOnHover then hsHover() end
+		elapsed = 0
+	end
+end)
+
+local eventframe = CreateFrame("Frame")
+eventframe:RegisterEvent("PLAYER_ENTERING_WORLD")
+eventframe:RegisterEvent("BAG_UPDATE")
+eventframe:RegisterEvent("HEARTHSTONE_BOUND")
+eventframe:RegisterEvent("MODIFIER_STATE_CHANGED")
+
+eventframe:SetScript("OnEvent", function(this, event, arg1, arg2, arg3, arg4, ...)
+if InCombatLockdown() then return end
+
+HSText:SetText(strupper(GetBindLocation()))
+HSFrame:SetSize(HSText:GetStringWidth()+16, 16)
+
+
+if IsUsableItem(110560) then
+	garrisonFrame:Show()
+else
+	garrisonFrame:Hide()
+end
+
+if event == "MODIFIER_STATE_CHANGED" then
+	if arg1 == "LSHIFT" or arg1 == "RSHIFT" then
+		if arg2 == 1 then
+			if IsUsableItem(128353) then
+				garrisonText:SetText("SHIPYARD")
+				garrisonIcon:SetTexture(cfg.mediaFolder.."datatexts\\shipcomp")
+			end
+		elseif arg2 == 0 then
+			garrisonText:SetText("GARRISON")
+			garrisonIcon:SetTexture(cfg.mediaFolder.."datatexts\\garr")
+		end
+	end
+end
+	garrisonFrame:SetSize(garrisonText:GetStringWidth()+16, 16)
+	teleportFrame:SetSize(HSFrame:GetWidth()+garrisonFrame:GetWidth()+8, 16)
+end)
diff --git a/modules/travel.lua b/modules/travel.lua
new file mode 100644
index 0000000..282dca4
--- /dev/null
+++ b/modules/travel.lua
@@ -0,0 +1,329 @@
+local AddOnName, XIVBar = ...;
+local _G = _G;
+local xb = XIVBar;
+local L = XIVBar.L;
+
+local TravelModule = xb:NewModule("TravelModule", 'AceEvent-3.0')
+
+function TravelModule:GetName()
+  return L['Travel'];
+end
+
+function TravelModule:OnInitialize()
+  self.iconPath = xb.constants.mediaPath..'datatexts\\repair'
+  self.garrisonHearth = 110560
+  self.hearthstones = {
+    64488, -- Innkeeper's Daughter
+    54452, -- Ethereal Portal
+    93672, -- Dark Portal
+    6948,  -- Hearthstone
+    556,   -- Astral Recall
+    28585, -- Ruby Slippers
+    37118, -- Scroll of Recall 1
+    44314, -- Scroll of Recall 2
+    44315, -- Scroll of Recall 3
+  }
+  self.portOptions = {
+    -- dalaran rings, guild capes?
+    {portId = 128353, text = GARRISON_LOCATION_TOOLTIP}, -- admiral's compass
+    {portId = 140192, text = GetMapNameByID(1014)}, -- dalaran hearthstone
+    {portId = self.garrisonHearth, text = GARRISON_LOCATION_TOOLTIP}, -- needs to be var for default options
+  }
+
+  if xb.constants.playerClass == 'DRUID' then
+    if IsPlayerSpell(193753) then
+      tinsert(self.portOptions, {portId = 193753, text = ORDER_HALL_DRUID})
+    else
+      tinsert(self.portOptions, {portId = 18960, text = GetMapNameByID(241)})
+    end
+  end
+
+  if xb.constants.playerClass == 'DEATHKNIGHT' then
+    tinsert(self.portOptions, {portId = 50977, text = ORDER_HALL_DEATHKNIGHT})
+  end
+
+  if xb.constants.playerClass == 'MAGE' then
+    tinsert(self.portOptions, {portId = 193759, text = ORDER_HALL_MAGE})
+  end
+
+  if xb.constants.playerClass == 'MONK' then
+    local portText = GetMapNameByID(809)
+    if IsPlayerSpell(200617) then
+      portText = ORDER_HALL_MONK
+    end
+    tinsert(self.portOptions, {portId = 193759, text = portText})
+  end
+
+  self.portButtons = {}
+end
+
+function TravelModule:OnEnable()
+  if self.hearthFrame == nil then
+    self.hearthFrame = CreateFrame("FRAME", nil, xb:GetFrame('bar'))
+    xb:RegisterFrame('hearthFrame', self.hearthFrame)
+  end
+  self:CreateFrames()
+  self:RegisterFrameEvents()
+  self:Refresh()
+end
+
+function TravelModule:OnDisable()
+end
+
+function TravelModule:CreateFrames()
+  self.hearthButton = self.hearthButton or CreateFrame('BUTTON', nil, self.hearthFrame, "SecureActionButtonTemplate")
+  self.hearthIcon = self.hearthIcon or self.hearthButton:CreateTexture(nil, 'OVERLAY')
+  self.hearthText = self.hearthText or self.hearthButton:CreateFontString(nil, 'OVERLAY')
+
+  self.portButton = self.portButton or CreateFrame('BUTTON', nil, self.hearthFrame, "SecureActionButtonTemplate")
+  self.portIcon = self.portIcon or self.portButton:CreateTexture(nil, 'OVERLAY')
+  self.portText = self.portText or self.portButton:CreateFontString(nil, 'OVERLAY')
+
+  self.portPopup = self.portPopup or CreateFrame('BUTTON', nil, self.portButton)
+  self.popupTexture = self.popupTexture or self.portPopup:CreateTexture(nil, 'BACKGROUND')
+end
+
+function TravelModule:RegisterFrameEvents()
+  self.hearthButton:EnableMouse(true)
+  self.hearthButton:RegisterForClicks("AnyUp")
+  self.hearthButton:SetAttribute('*type', 'macro')
+
+  self.portButton:EnableMouse(true)
+  self.portButton:RegisterForClicks("AnyUp")
+  self.portButton:SetAttribute('type1', 'macro')
+  self.portButton:SetAttribute('type2', 'portFunction')
+
+  self.portPopup:EnableMouse(true)
+  self.portPopup:RegisterForClicks('RightButtonUp')
+
+  self.portButton.portFunction = self.portButton.portFunction or function()
+    if TravelModule.portPopup:IsVisible() then
+      TravelModule.portPopup:Hide()
+    else
+      TravelModule:CreatePortPopup()
+      TravelModule.portPopup:Show()
+    end
+  end
+
+  self.portPopup:SetScript('OnClick', function(self, button)
+    if button == 'RightButton' then
+      self:Hide()
+    end
+  end)
+
+  self.hearthButton:SetScript('OnEnter', function()
+    TravelModule:SetHearthColor()
+  end)
+
+  self.hearthButton:SetScript('OnLeave', function()
+    TravelModule:SetHearthColor()
+  end)
+
+  self.portButton:SetScript('OnEnter', function()
+    TravelModule:SetPortColor()
+  end)
+
+  self.portButton:SetScript('OnLeave', function()
+    TravelModule:SetPortColor()
+  end)
+end
+
+function TravelModule:SetHearthColor()
+  if InCombatLockdown() then return; end
+
+  local db = xb.db.profile
+  if self.hearthButton:IsMouseOver() then
+    self.hearthText:SetTextColor(unpack(xb:HoverColors()))
+  else
+    self.hearthIcon:SetVertexColor(db.color.inactive.r, db.color.inactive.g, db.color.inactive.b, db.color.inactive.a)
+    local hearthName = ''
+    local hearthActive = false
+    for i,v in ipairs(self.hearthstones) do
+      if (PlayerHasToy(v) or IsUsableItem(v)) then
+        if GetItemCooldown(v) == 0 then
+          hearthName, _ = GetItemInfo(v)
+          hearthActive = true
+          self.hearthButton:SetAttribute("macrotext", "/cast "..tostring(v))
+          break
+        end
+      end -- if toy/item
+      if IsPlayerSpell(v) then
+        if GetSpellCooldown(v) == 0 then
+          hearthName, _ = GetSpellInfo(v)
+          hearthActive = true
+          self.hearthButton:SetAttribute("macrotext", "/cast "..tostring(v))
+        end
+      end -- if is spell
+    end -- for hearthstones
+    if hearthActive then
+      self.hearthIcon:SetVertexColor(db.color.normal.r, db.color.normal.g, db.color.normal.b, db.color.normal.a)
+    end
+    self.hearthText:SetTextColor(db.color.inactive.r, db.color.inactive.g, db.color.inactive.b, db.color.inactive.a)
+  end --else
+end
+
+function TravelModule:SetPortColor()
+  if InCombatLockdown() then return; end
+
+  local db = xb.db.profile
+  local v = db.modules.travel.portItem.portId
+
+  if not (IsUsableItem(v) or IsPlayerSpell(v)) then
+    self.portButton:Hide()
+    return
+  end
+
+  if self.portButton:IsMouseOver() then
+    self.portText:SetTextColor(unpack(xb:HoverColors()))
+  else
+    local hearthname = ''
+    local hearthActive = false
+    if (PlayerHasToy(v) or IsUsableItem(v)) then
+      if GetItemCooldown(v) == 0 then
+        hearthName, _ = GetItemInfo(v)
+        hearthActive = true
+        self.portButton:SetAttribute("macrotext", "/cast "..tostring(v))
+      end
+    end -- if toy/item
+    if IsPlayerSpell(v) then
+      if GetSpellCooldown(v) == 0 then
+        hearthName, _ = GetSpellInfo(v)
+        hearthActive = true
+        self.portButton:SetAttribute("macrotext", "/cast "..tostring(v))
+      end
+    end -- if is spell
+
+    if hearthActive then
+      self.portIcon:SetVertexColor(db.color.normal.r, db.color.normal.g, db.color.normal.b, db.color.normal.a)
+    else
+      self.portIcon:SetVertexColor(db.color.inactive.r, db.color.inactive.g, db.color.inactive.b, db.color.inactive.a)
+    end
+    self.portText:SetTextColor(db.color.inactive.r, db.color.inactive.g, db.color.inactive.b, db.color.inactive.a)
+  end --else
+end
+
+function TravelModule:CreatePortPopup()
+  if not self.portPopup then return; end
+
+  local db = xb.db.profile
+  local popupWidth = self.portPopup:GetWidth()
+  local popupHeight = xb.constants.popupPadding
+  local changedWidth = false
+  for i, v in ipairs(self.portOptions) do
+    if self.portButtons[v.portId] == nil then
+      if IsUsableItem(v.portId) or IsPlayerSpell(v.portId) then
+        local button = CreateFrame('BUTTON', nil, self.portPopup)
+        local buttonText = button:CreateFontString(nil, 'OVERLAY')
+
+        buttonText:SetFont(xb.LSM:Fetch(xb.LSM.MediaType.FONT, db.text.font), db.text.fontSize)
+        buttonText:SetTextColor(db.color.inactive.r, db.color.inactive.g, db.color.inactive.b, db.color.inactive.a)
+        buttonText:SetText(v.text)
+        buttonText:SetPoint('LEFT')
+        local textWidth = buttonText:GetStringWidth()
+
+        button:SetID(v.portId)
+        button:SetSize(textWidth, db.text.fontSize)
+        button.isSettable = true
+        button.portItem = v
+
+        button:EnableMouse(true)
+        button:RegisterForClicks('LeftButtonUp')
+
+        button:SetScript('OnEnter', function()
+          buttonText:SetTextColor(db.color.normal.r, db.color.normal.g, db.color.normal.b, db.color.normal.a)
+        end)
+
+        button:SetScript('OnLeave', function()
+          buttonText:SetTextColor(db.color.inactive.r, db.color.inactive.g, db.color.inactive.b, db.color.inactive.a)
+        end)
+
+        button:SetScript('OnClick', function(self)
+          xb.db.profile.modules.travel.portItem = self.portItem
+          TravelModule:Refresh()
+        end)
+
+        self.portButtons[v.portId] = button
+
+        if textWidth > popupWidth then
+          popupWidth = textWidth
+          changedWidth = true
+        end
+      end -- if usable item or spell
+    else
+      if not (IsUsableItem(v.portId) or IsPlayerSpell(v.portId)) then
+        self.portButtons[v.portId].isSettable = false
+      end
+    end -- if nil
+  end -- for ipairs portOptions
+  for portId, button in pairs(self.portButtons) do
+    if button.isSettable then
+      button:SetPoint('LEFT', xb.constants.popupPadding, 0)
+      button:SetPoint('TOP', 0, -(popupHeight + xb.constants.popupPadding))
+      popupHeight = popupHeight + xb.constants.popupPadding + db.text.fontSize
+    else
+      button:Hide()
+    end
+  end -- for id/button in portButtons
+  if changedWidth then
+    popupWidth = popupWidth + (xb.constants.popupPadding * 3)
+  end
+
+  if popupWidth < self.portButton:GetWidth() then
+    popupWidth = self.portButton:GetWidth()
+  end
+  self.portPopup:SetSize(popupWidth, popupHeight + xb.constants.popupPadding)
+end
+
+function TravelModule:Refresh()
+  if self.hearthFrame == nil then return; end
+
+  local db = xb.db.profile
+  --local iconSize = (xb:GetHeight() / 2)
+  local iconSize = db.text.fontSize + db.general.barPadding
+
+  self.hearthText:SetFont(xb.LSM:Fetch(xb.LSM.MediaType.FONT, db.text.font), db.text.fontSize)
+  self.hearthText:SetText(GetBindLocation())
+
+  self.hearthButton:SetSize(self.hearthText:GetWidth() + iconSize + db.general.barPadding, xb:GetHeight())
+  self.hearthButton:SetPoint("RIGHT")
+
+  self.hearthText:SetPoint("RIGHT")
+
+  self.hearthIcon:SetTexture(xb.constants.mediaPath..'datatexts\\hearth')
+  self.hearthIcon:SetSize(iconSize, iconSize)
+
+  self.hearthIcon:SetPoint("RIGHT", self.hearthText, "LEFT", -(db.general.barPadding), 0)
+
+  self:SetHearthColor()
+
+  self.portText:SetFont(xb.LSM:Fetch(xb.LSM.MediaType.FONT, db.text.font), db.text.fontSize)
+  self.portText:SetText(db.modules.travel.portItem.text)
+
+  self.portButton:SetSize(self.portText:GetWidth() + iconSize + db.general.barPadding, xb:GetHeight())
+  self.portButton:SetPoint("LEFT", -(db.general.barPadding), 0)
+
+  self.portText:SetPoint("RIGHT")
+
+  self.portIcon:SetTexture(xb.constants.mediaPath..'datatexts\\garr')
+  self.portIcon:SetSize(iconSize, iconSize)
+
+  self.portIcon:SetPoint("RIGHT", self.portText, "LEFT", -(db.general.barPadding), 0)
+
+  self:SetPortColor()
+
+  self:CreatePortPopup()
+  self.portPopup:SetPoint('BOTTOM', self.portButton, 'TOP', 0, xb.constants.popupPadding)
+  local mainTexture = string.sub(xb.frames.bgTexture:GetTexture(), 7)
+  self.popupTexture:SetColorTexture(xb:HexToRGBA(mainTexture))
+  self.popupTexture:SetAllPoints()
+  self.portPopup:Hide()
+
+  self.hearthFrame:SetSize(self.hearthButton:GetWidth() + self.portButton:GetWidth() + db.general.barPadding, xb:GetHeight())
+  self.hearthFrame:SetPoint("RIGHT", -(db.general.barPadding), 0)
+end
+
+function TravelModule:GetDefaultOptions()
+  return 'travel', {
+    portItem = {portId = self.garrisonHearth, text = GARRISON_LOCATION_TOOLTIP}
+  }
+end