Go to Page... |
Thread Tools | Display Modes |
04-23-11, 04:46 AM | #1 |
addon disable if a spell is usable
Hy ,
i searching for a script that disable my addon if a spell is usable. can someone help me ? Code:
if IsUsableSpell(77746) then newMode = Exit_MODE; end if newMode == Exit_MODE then -- ???? disable ("my addon") end |
|
04-23-11, 05:52 AM | #2 |
Code:
if IsUsableSpell(77746) then addon:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED") addon:SetScript("OnUpdate", function() end) end |
|
04-23-11, 09:10 AM | #3 |
nothing happens
i think its better to bring more informations here.. so that what i try is do deactivate the script if i can cast Manatite (restro) or Totemic Wrath (ele) Manatide id = 16190 Totemic Wrath id = 77746 here is the script i try to updatet there is still an check / update if a player change his skilltree but i don't find the right lua to manage it Code:
-- -- ShamWow_Enhance ShamWow_Enhance = LibStub( "AceAddon-3.0" ):NewAddon( "ShamWow_Enhance", "AceConsole-3.0", "AceEvent-3.0" ); local media = LibStub:GetLibrary("LibSharedMedia-3.0"); local mainFrame, cooldownFrame, cooldownFrame1, cooldownFrame2, target, timeText; local ENHANCE_MODE = 1; local mode = 0; local lastFlameShockCast = 0; local TEXT = "Melee Addon nicht aktiv" local TEXT = "Melee Addon aktiv" local function swPrint(s) DEFAULT_CHAT_FRAME:AddMessage("ShamWow_Enhance: ".. tostring(s)); end -- spell info local stormstrikeId = 17364; local lavalashId = 60103; local earthshockId = 8042; local maelstromId = 51530; local windfuryId = 8232; local flametongueId = 8024; local lightningBoltId = 403; local clearcastId = 16246; local lightningshieldId = 324; local shamanisticRageId = 30823; local sengendeflammenId = 77657; local feralSpiritId = 51533; local unleashelementsId = 73680; local naturesSwiftnessId = 17116; local flameshockId = 8050; local totemOfWrathId = 77746; local searingtotemId = 3599; local totemOfWrathName = GetSpellInfo(totemOfWrathId); local sengendeflammenName = GetSpellInfo(sengendeflammenId); local flameshockName = GetSpellInfo(flameshockId); local naturesSwiftnessName = GetSpellInfo(naturesSwiftnessId); local clearcastName = GetSpellInfo(clearcastId); local feralSpiritName = GetSpellInfo(feralSpiritId); local autoattackName = "Attack"; -- fixme does this have an id? local stormstrikeName = GetSpellInfo(stormstrikeId); local lavalashName = GetSpellInfo(lavalashId); local earthshockName = GetSpellInfo(earthshockId); local maelstromName = GetSpellInfo(maelstromId); local lightningBoltName = GetSpellInfo(lightningBoltId); local windfuryName = GetSpellInfo(windfuryId); local flametongueName = GetSpellInfo(flametongueId); local lightningshieldName = GetSpellInfo(lightningshieldId); local cooldownSpellName = lightningBoltName; local shamanisticRageName = GetSpellInfo(shamanisticRageId); local unleashelementsName = GetSpellInfo(unleashelementsId); local searingtotemName = GetSpellInfo(searingtotemId); local spellQueue = {}; local maxQueueSize = 4; local groupCount = 0; local hostile = false; local timeLeft = 0; local inCombat = false; -- configs local defaults = { char = { x = 0, y = 0, relativePoint = "CENTER", mode = 1, size = 50, spacing = 15, locked = false, threatThreshold = 70, updateFrequency = .2 } }; -- random variables local playerId; local function canCastSpell(spellName, time) local startTime, duration = GetSpellCooldown(spellName); if duration then local nextCastTime = startTime + duration; return nextCastTime <= time; end end function soonestCooldown(...) local castInfo = {}; for i=1,select('#',...) do local spellName = select(i, ...); local startTime, duration = GetSpellCooldown(spellName); if duration then local nextCastTime = startTime + duration; if castInfo.castTime == nil or castInfo.castTime > nextCastTime then castInfo.castTime = nextCastTime; castInfo.spell = spellName; end end end return castInfo; end function ShamWow_Enhance:SaveLocation() point, relativeTo, relativePoint, xOfs, yOfs = mainFrame:GetPoint(); self.db.char.x = xOfs; self.db.char.y = yOfs; self.db.char.relativePoint = relativePoint; end local function RepositionFrames() for i=maxQueueSize,1,-1 do local spacing = ShamWow_Enhance.db.char.spacing; local f = spellQueueFrames[i]; f:SetWidth(ShamWow_Enhance.db.char.size) f:SetHeight(ShamWow_Enhance.db.char.size) if i == maxQueueSize then f:SetPoint("CENTER", spacing * (maxQueueSize-1), 0); else f:SetPoint("CENTER", -spacing, 0); end end end function ShamWow_Enhance:OnInitialize() local AceConfigReg = LibStub("AceConfigRegistry-3.0") local AceConfigDialog = LibStub("AceConfigDialog-3.0") self.db = LibStub("AceDB-3.0"):New("ShamWow_EnhanceDB", defaults, "char") LibStub("AceConfig-3.0"):RegisterOptionsTable("ShamWow_Enhance", self:GetOptions(), {"ShamWow_Enhance", "swe"} ) self.optionsFrame = AceConfigDialog:AddToBlizOptions("ShamWow_Enhance","ShamWow_Enhance") self.db:RegisterDefaults(defaults); mainFrame = CreateFrame("Frame","ShamWow_EnhanceDisplayFrame",UIParent) mainFrame:SetFrameStrata("BACKGROUND") mainFrame:SetWidth(self.db.char.size) mainFrame:SetHeight(self.db.char.size) mainFrame:EnableMouse(true) mainFrame:SetMovable(true) mainFrame:SetClampedToScreen(true) mainFrame:SetScript("OnMouseDown", function(self) if not ShamWow_Enhance.db.char.locked then self:StartMoving(); end end); mainFrame:SetScript("OnMouseUp", function(self) self:StopMovingOrSizing(); ShamWow_Enhance:SaveLocation(); end); mainFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing(); ShamWow_Enhance:SaveLocation(); end) mainFrame:ClearAllPoints(); mainFrame:SetPoint(self.db.char.relativePoint, self.db.char.x, self.db.char.y); spellQueueFrames = {}; for i=maxQueueSize,1,-1 do local parentFrame; if i == maxQueueSize then parentFrame = mainFrame; else parentFrame = spellQueueFrames[i+1]; end local f = CreateFrame("Frame","ShamWow_EnhanceDisplayFrame" .. i, parentFrame) f:SetFrameStrata("BACKGROUND") f:SetWidth(self.db.char.size) f:SetHeight(self.db.char.size) f:EnableMouse(false) f:SetMovable(false) f:SetClampedToScreen(true) f:ClearAllPoints(); local spacing = ShamWow_Enhance.db.char.spacing; f.spellTexture = f:CreateTexture(nil,"BACKGROUND"); f.spellTexture:SetAllPoints(f); f.overlayTexture = f:CreateTexture(nil,"OVERLAY"); f.overlayTexture:SetAllPoints(f); spellQueueFrames[i] = f; end cooldownFrame1 = CreateFrame("Frame","ShamWow_ClearCastFrame", spellQueueFrames[1]) cooldownFrame1:SetFrameStrata("BACKGROUND") local ccSize = self.db.char.size / 2; cooldownFrame1:SetWidth(ccSize); cooldownFrame1:SetHeight(ccSize); cooldownFrame1:SetPoint("TOPLEFT", -ccSize, 0); cooldownFrame1:EnableMouse(false) cooldownFrame1:SetMovable(false) cooldownFrame1:SetClampedToScreen(true) cooldownFrame1.texture = cooldownFrame1:CreateTexture(nil,"OVERLAY"); cooldownFrame1.texture:SetAllPoints(cooldownFrame1); cooldownFrame2 = CreateFrame("Frame","ShamWow_FeralSpiritFrame", spellQueueFrames[1]) cooldownFrame2:SetFrameStrata("BACKGROUND") cooldownFrame2:SetWidth(ccSize); cooldownFrame2:SetHeight(ccSize); cooldownFrame2:SetPoint("TOPLEFT", -ccSize, -ccSize); cooldownFrame2:EnableMouse(false) cooldownFrame2:SetMovable(false) cooldownFrame2:SetClampedToScreen(true) cooldownFrame2.texture = cooldownFrame2:CreateTexture(nil,"OVERLAY"); cooldownFrame2.texture:SetAllPoints(cooldownFrame2); cooldownFrame = CreateFrame("Cooldown","$parent_cooldown", spellQueueFrames[1]); cooldownFrame:SetAllPoints(mainFrame); local testfont = media:Fetch("font", 'Arial'); if not mainFrame.text then mainFrame.text = mainFrame:CreateFontString(nil,"OVERLAY") end mainFrame.text:SetFont(testfont, 12, "THICKOUTLINE"); mainFrame.text:ClearAllPoints() mainFrame.text:SetTextColor(.8, 0, 0, 1) mainFrame.text:SetPoint("BOTTOM", mainFrame, "BOTTOM", 0, -13); mainFrame.text:SetText("") if not mainFrame.alertText then mainFrame.alertText = mainFrame:CreateFontString(nil,"OVERLAY") end mainFrame.alertText:SetFont(testfont, 12, "THICKOUTLINE"); mainFrame.alertText:ClearAllPoints() mainFrame.alertText:SetTextColor(1, 1, 0, 1) mainFrame.alertText:SetPoint("BOTTOM", mainFrame, "TOP", 5, 2); mainFrame.alertText:SetText("") timeText = spellQueueFrames[1]:CreateFontString(nil,"OVERLAY") timeText:SetFont(testfont, 12, "THICKOUTLINE"); timeText:ClearAllPoints() timeText:SetTextColor(0, 1, 0, 1) timeText:SetPoint("CENTER", mainFrame, "CENTER", 0, 0); timeText:SetText("") RepositionFrames(); swPrint('Initialized'); end local function AlertCheck() if (not hostile) or groupCount == 0 or ShamWow_Enhance.db.char.threatThreshold > 100 then mainFrame.text:SetText(""); else local _,_,threatpct,_,_ = UnitDetailedThreatSituation("player", "target"); if not threatpct or threatpct < ShamWow_Enhance.db.char.threatThreshold then mainFrame.text:SetText(""); else mainFrame.text:SetText(string.format("%.0f", threatpct) .. '%'); end end local nastySpellName = ""; -- for tracking nasty spell reflect debuffs if (hostile) then -- check target buffs for i=1,40 do local name = UnitBuff("target", i); if not name then break; -- end of buffs end if name:lower():find('reflect') then nastySpellName = name; break; end end end mainFrame.alertText:SetText(nastySpellName); end -- this colors the overlay frame based on range, mana local function FrameStatusCheck(f, spell) if spell == autoattackName or IsSpellInRange(spell, 'target') == 0 then f.overlayTexture:SetTexture(1, 0, 0, .5); else name, _, _, cost = GetSpellInfo(spell); if cost and UnitPower('player') < cost then f.overlayTexture:SetTexture(0, 0, 1, .5); else f.overlayTexture:SetTexture(nil); end end end function ShamWow_Enhance:PARTY_MEMBERS_CHANGED(...) groupCount = GetNumRaidMembers(); if groupCount == 0 then groupType = "party"; groupCount = GetNumPartyMembers(); else groupType = "raid"; groupCount = groupCount - 1; -- don't include yourself end end local function addSpell(spellName) spellQueue[#spellQueue+1] = spellName; end local function RecalcEnhanceQueue(nextCastTime) local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo(); if not hasMainHandEnchant then addSpell(windfuryName); end if (not hasOffHandEnchant) and OffhandHasWeapon() then addSpell(flametongueName); end -- check target debuffs local hasSSDebuff = false; local hasFSDebuff = false; for i=1,40 do local name, _, _, _, _, _, _, isMine = UnitDebuff("target", i); if not name then break; -- end of debuffs end if isMine == "player" and name == flameshockName then hasFSDebuff = true; end if isMine == "player" and name == stormstrikeName then hasSSDebuff = true; end end -- check buffs local ccTexture = nil; local hasShield = false; local maelstrom = false; for i=1,40 do local name, _, texture, count = UnitBuff("player", i); if not name then break; -- end of buffs end if name == maelstromName then if hostile and count == 5 then maelstrom = true; end elseif name == lightningshieldName then hasShield = true; elseif name == clearcastName then ccTexture = texture; end end if true or ccTexture then cooldownFrame1.texture:SetTexture(ccTexture); else cooldownFrame1.texture:SetTexture(0, 1, 0, .5); end if inCombat and canCastSpell(feralSpiritName, nextCastTime) then cooldownFrame2.texture:SetTexture(GetSpellTexture(feralSpiritName)); else cooldownFrame2.texture:SetTexture(nil); end -- Searing Totem local hasSFDebuff = false; for i=1,40 do local name, _, _, _, _, _, _, isMine = UnitDebuff("target", i); if not name then break; -- end of debuffs end if isMine == "player" and name == sengendeflammenName then hasSFDebuff = true; end end if hasSFDebuff == false then if inCombat and canCastSpell(searingtotemName, nextCastTime) then cooldownFrame1.texture:SetTexture(GetSpellTexture(searingtotemName)); end else cooldownFrame1.texture:SetTexture(nil); end -- End of Searing Totem if (not inCombat) and (not hasShield) then addSpell(lightningshieldName); end --local haveTotem, nameTotem, startTimeTotem, durationTotem, iconTotem = GetTotemInfo(1); --local magmaTotemCastable = false; -- if inCombat and (not haveTotem) then -- addSpell(lightningshieldName); -- end local mana = UnitPower('player'); local maxMana = UnitPowerMax('player'); if hostile then local ranged = IsSpellInRange(stormstrikeName, 'target') == 0; local earthshockCastable = canCastSpell(earthshockName, nextCastTime); local stormstrikeCastable = canCastSpell(stormstrikeName, nextCastTime); local lavalashCastable = canCastSpell(lavalashName, nextCastTime); local maelstromFirst = maelstrom and (hasSSDebuff or ranged); if lavalashCastable then addSpell(lavalashName); end local maelstromSpell = lightningBoltName; if maelstrom then if canCastSpell(lightningBoltName, nextCastTime) then maelstromSpell = lightningBoltName; end end if maelstromFirst then addSpell(maelstromSpell); end if ranged then if earthshockCastable then if hasFSDebuff == false then addSpell(flameshockName); else addSpell(earthshockName); end elseif (not stormstrikeCastable) and (not lavalashCastable) then addSpell(autoattackName); end end if maelstrom and (not maelstromFirst) then addSpell(maelstromSpell); end -- if ranged == false and earthshockCastable then -- if hasFSDebuff == false then -- addSpell(flameshockName); -- else -- addSpell(earthshockName); -- end -- end if ranged == false and earthshockCastable then if hasFSDebuff == false then addSpell(flameshockName); end end if stormstrikeCastable then addSpell(stormstrikeName); end if ranged == false and earthshockCastable then if hasFSDebuff == true then addSpell(earthshockName); end end if canCastSpell(unleashelementsName, nextCastTime) then addSpell(unleashelementsName); end else local health = UnitHealth('player'); local maxHealth = UnitHealthMax('player'); if health < (.6 * maxHealth) then addSpell(healingWaveName); elseif (not inCombat) and (mana >= (.90 * maxMana) or ccTexture) and health < (.75 * maxHealth) then addSpell(healingWaveName); -- heal yoself foo! end end if inCombat and not hasShield then addSpell(lightningshieldName); end end local function RecalcSpell() if (not inCombat) then ShamWow_Enhance:RecalcMode(); -- check if you switched spec end AlertCheck(); spellQueue = {}; local startTime, duration = GetSpellCooldown(cooldownSpellName); local curTime = GetTime(); local nextCastTime = curTime; if duration > 0 then local gcdEndTime = startTime + duration; if gcdEndTime > curTime then nextCastTime = gcdEndTime; end cooldownFrame:SetCooldown(startTime, duration); cooldownFrame:SetAlpha(1); if mode == ELEM_MODE then -- we don't want to recalc too close to the last cast if curTime - startTime < .5 then return; end end else cooldownFrame:SetAlpha(0); end local _, _, _, _, _, spellEndTime = UnitCastingInfo('player'); if spellEndTime then nextCastTime = math.min(nextCastTime, spellEndTime / 1000); end --local possessed = GetActionTexture(121); --if possessed ~= nil then -- do nothing if mode == RESTO_MODE then RecalcRestoQueue(nextCastTime); elseif mode == ELEM_MODE then RecalcElemQueue(nextCastTime); else RecalcEnhanceQueue(nextCastTime); end for i=maxQueueSize,1,-1 do local spell = spellQueue[i]; local f = spellQueueFrames[i]; if spell then f.spellTexture:SetTexture(GetSpellTexture(spellQueue[i])); FrameStatusCheck(f,spell); else f.spellTexture:SetTexture(nil); f.overlayTexture:SetTexture(nil); end end local timeTextStr = ''; if inCombat or hostile then timeLeft = ShamWow_Enhance.db.char.updateFrequency; else timeLeft = .5; end if #spellQueue == 0 then if (not possessed) and hostile and mode == ENHANCE_MODE then local castInfo = soonestCooldown(stormstrikeName, earthshockName, lavalashName); local timeUntilCast = castInfo.castTime - GetTime(); if timeUntilCast < timeLeft then timeLeft = timeUntilCast; end if timeUntilCast < 1 then local f = spellQueueFrames[1]; f.overlayTexture:SetTexture(.5, .5, .5, .5); f.spellTexture:SetTexture(GetSpellTexture(castInfo.spell)); timeTextStr = string.format("%0.1f", timeUntilCast); else cooldownFrame:SetAlpha(0); end else cooldownFrame:SetAlpha(0); end end timeText:SetText(timeTextStr); end function ShamWow_Enhance:RecalcMode(...) end function ShamWow_Enhance:PLAYER_REGEN_ENABLED(...) inCombat = false; end function ShamWow_Enhance:PLAYER_REGEN_DISABLED(...) inCombat = true; ShamWow_Enhance:PLAYER_TARGET_CHANGED(); -- recompute if target is friend when combat starts end function ShamWow_Enhance:PLAYER_TARGET_CHANGED(...) hostile = UnitName("target") and UnitCanAttack("player","target") and UnitHealth("target") > 0; timeLeft = 0; end function ShamWow_Enhance:OnEnable() local playerClass, englishClass = UnitClass("player"); if englishClass ~= 'SHAMAN' then swPrint('You are not a shaman. Please disable ShamWow_Enhance as an Addon for this character'); DisableAddon("ShamWow_Enhance"); else playerId = UnitGUID("player"); self:PARTY_MEMBERS_CHANGED(); -- recheck party members self:PLAYER_TARGET_CHANGED(); -- check target self:RecalcMode(); -- Register for Function Events self:UnregisterAllEvents(); self:RegisterEvent("PLAYER_TARGET_CHANGED"); self:RegisterEvent("PLAYER_REGEN_ENABLED"); self:RegisterEvent("PLAYER_REGEN_DISABLED"); self:RegisterEvent("PARTY_MEMBERS_CHANGED"); mainFrame:SetScript('OnUpdate', function(self, timeSinceLast) timeLeft = timeLeft - timeSinceLast; if timeLeft <= 0 then RecalcSpell(); end end); swPrint('Enabled'); end end function ShamWow_Enhance:OnDisable() mainFrame:SetScript('OnUpdate', nil); swPrint(' disabled'); end function ShamWow_Enhance:GetProperty(info) local propName = info[#info]; local value = self.db.char[propName]; return value; end function ShamWow_Enhance:SetProperty(info, newValue) local propName = info[#info]; self.db.char[propName] = newValue; if propName == 'spacing' or propName == 'size' then RepositionFrames(); end if mainFrame and propName == 'size' then mainFrame:SetWidth(self.db.char.size); mainFrame:SetHeight(self.db.char.size); end end function ShamWow_Enhance:GetOptions() local options = { name = "ShamWow_Enhance", handler = ShamWow_Enhance, type = 'group', childGroups ='tree', args = { locked = { type = "toggle", name = "Locked", get = "GetProperty", set = "SetProperty", order = 0, }, mode = { type = 'select', name = "Mode", values = { 'Enhancement', 'Heal', 'Elemental', 'Auto' }, get = "GetProperty", set = "SetProperty", order = 1, }, size = { type = "range", name = "Size", desc = "Size of the Frame", min = 1, max = 200, step = 1, get = "GetProperty", set = "SetProperty", order = 2, }, updateFrequency = { type = 'range', name = "Update Frequency", desc = "The delay in seconds to wait before rechecking the next spell.", min = .05, max = .5, step = .05, get = "GetProperty", set = "SetProperty", order = 3, }, spacing = { type = 'range', name = "Button Spacing", min = 1, max = 200, step = 1, get = "GetProperty", set = "SetProperty", order = 4, }, threatThreshold = { type = 'range', name = "Threat", desc = "Show threat if your threat percentage is atleast this amount. 100% means you have aggro! Set to 101 if you don't want to see the threat indicator at all.", min = 0, max = 101, step = 1, get = "GetProperty", set = "SetProperty", order = 5, } }, } return options end |
|
04-23-11, 03:43 PM | #4 |
It seems you are trying to update the addon ShamWow_Enhance (Ace3), and added DisableAddOn in there
I don't know about DisableAddOn, but MyAddon:Disable() will disable it for the current session everytime the addon is loaded Code:
function ShamWow_Enhance:OnEnable() local playerClass, englishClass = UnitClass("player"); if englishClass ~= 'SHAMAN' then swPrint('You are not a shaman. Please disable ShamWow_Enhance as an Addon for this character'); ShamWow_Enhance:Disable() else playerId = UnitGUID("player"); self:PARTY_MEMBERS_CHANGED(); -- recheck party members self:PLAYER_TARGET_CHANGED(); -- check target self:RecalcMode(); -- Register for Function Events self:UnregisterAllEvents(); self:RegisterEvent("PLAYER_TARGET_CHANGED"); self:RegisterEvent("PLAYER_REGEN_ENABLED"); self:RegisterEvent("PLAYER_REGEN_DISABLED"); self:RegisterEvent("PARTY_MEMBERS_CHANGED"); mainFrame:SetScript('OnUpdate', function(self, timeSinceLast) timeLeft = timeLeft - timeSinceLast; if timeLeft <= 0 then RecalcSpell(); end end); swPrint('Enabled'); end end Edit: Lol, I had it wrong I guess Last edited by Ketho : 04-25-11 at 10:59 PM. |
|
04-23-11, 06:30 PM | #5 | |
You are basically trying to identify character's current spec, so instead of all this mombo-jumbo with watching which spells are available you should simply make a script that does just that ... identify your current spec. GetActiveTalentGroup() - returns your active talent 'spec' (1 or 2, i.e. primary or secondary) and then GetPrimaryTalentTree(false, false, GetActiveTalentGroup()) will return the number of primary talent tree of your currently active spec - and that's what you need. I know not every resto spec may include MTT (REALLY?!!) but iirc your add-on watches the actual cast of that ability so it should not really matter as identifying spec like this is the way to go. |
||
04-25-11, 09:50 PM | #6 |
thats realy nice
i must make some test with it. Code:
fuction load () local specc= 2 -- that specc when you are in melee local talent = GetActiveTalentGroup() local tree = GetPrimaryTalentTree(false, false, GetActiveTalentGroup()) if tree == specc then -- run addon elseif specc ~= 2 then -- stop addon and test the specc again end end |
|
04-25-11, 10:10 PM | #7 |
....
This just looks to see if you're in your primary spec (1) or secondary spec (2). Code:
local SpecToLookFor = 2 local f=CreateFrame("Frame") f:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED") f:SetScript("OnEvent" function(self,event) if GetActiveTalentGroup() == SpecToLookFor then --do stuff else --do other stuff end end) If you want to check for a specific spec or talent tree... You can use the tab index of the talent trees. For example, a Shaman with resto spec will have 3 as the return for GetPrimaryTalentTree() Code:
local TreeToLookFor = 3 local f=CreateFrame("Frame") f:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED") f:SetScript("OnEvent" function(self,event) local spec = GetActiveTalentGroup() if GetPrimaryTalentTree(false, false, spec)== TreeToLookFor then --do stuff for Resto else --do other stuff end end) |
|
WoWInterface » Developer Discussions » General Authoring Discussion » addon disable if a spell is usable |
«
Previous Thread
|
Next Thread
»
|
Display Modes |
Linear Mode |
Switch to Hybrid Mode |
Switch to Threaded Mode |
|
|