-- FishingBuddy -- -- Everything you wanted support for in your fishing endeavors -- Information for the stylin' fisherman local POLES = { ["Fishing Pole"] = "6256:0:0:0", ["Strong Fishing Pole"] = "6365:0:0:0", ["Darkwood Fishing Pole"] = "6366:0:0:0", ["Big Iron Fishing Pole"] = "6367:0:0:0", ["Blump Family Fishing Pole"] = "12225:0:0:0", ["Nat Pagle's Extreme Angler FC-5000"] = "19022:0:0:0", ["Arcanite Fishing Pole"] = "19970:0:0:0", -- yeah, so you can't really use these (for now :-) ["Dwarven Fishing Pole"] = "3567:0:0:0", ["Goblin Fishing Pole"] = "4598:0:0:0", } local FISHINGLURES = { ["6533:0:0:0"] = "Aquadynamic Fish Attractor", -- 100 for 5 mins ["7307:0:0:0"] = "Flesh Eating Worm", -- 75 for 10 mins ["6532:0:0:0"] = "Bright Baubles", -- 75 for 10 mins ["6811:0:0:0"] = "Aquadynamic Fish Lens", -- 50 for 10 mins ["6530:0:0:0"] = "Nightcrawlers", -- 50 for 10 mins ["6529:0:0:0"] = "Shiny Bauble", -- 25 for 10 mins } FishingBuddy.OPTIONS = { { ["name"] = "ShowNewFishies", ["text"] = FishingBuddy.CONFIG_SHOWNEWFISHIES_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_SHOWNEWFISHIES_INFO, ["default"] = 1 }, { ["name"] = "WatchFishies", ["text"] = FishingBuddy.CONFIG_FISHWATCH_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_FISHWATCH_INFO, ["default"] = 1 }, { ["name"] = "WatchCurrentSkill", ["text"] = FishingBuddy.CONFIG_FISHWATCHSKILL_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_FISHWATCHSKILL_INFO, ["default"] = 1 }, { ["name"] = "WatchCurrentZone", ["text"] = FishingBuddy.CONFIG_FISHWATCHZONE_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_FISHWATCHZONE_INFO, ["default"] = 0 }, { ["name"] = "WatchOnlyWhenFishing", ["text"] = FishingBuddy.CONFIG_FISHWATCHONLY_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_FISHWATCHONLY_INFO, ["default"] = 1 }, { ["name"] = "WatchFishPercent", ["text"] = FishingBuddy.CONFIG_FISHWATCHPERCENT_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_FISHWATCHPERCENT_INFO, ["default"] = 1 }, { ["name"] = "SortByPercent", ["text"] = FishingBuddy.CONFIG_SORTBYPERCENT_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_SORTBYPERCENT_INFO, ["default"] = 1 }, { ["name"] = "SuitUpFirst", ["text"] = FishingBuddy.CONFIG_SUITUPFIRST_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_SUITUPFIRST_INFO, ["default"] = 0 }, { ["name"] = "EasyCast", ["text"] = FishingBuddy.CONFIG_EASYCAST_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_EASYCAST_INFO, ["default"] = 1 }, { ["name"] = "FastCast", ["text"] = FishingBuddy.CONFIG_FASTCAST_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_FASTCAST_INFO, ["default"] = 1 }, { ["name"] = "EasyLures", ["text"] = FishingBuddy.CONFIG_EASYLURES_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_EASYLURES_INFO, ["default"] = 0 }, { ["name"] = "STVTimer", ["text"] = FishingBuddy.CONFIG_STVTIMER_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_STVTIMER_INFO, ["default"] = 0 }, { ["name"] = "UseButtonHole", ["text"] = FishingBuddy.CONFIG_USEBUTTONHOLE_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_USEBUTTONHOLE_INFO, ["default"] = 0, ["check"] = function () return ButtonHole ~= nil; end, ["checkfail"] = 0 }, { ["name"] = "MinimapButtonVisible", ["text"] = FishingBuddy.CONFIG_MINIMAPBUTTON_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_MINIMAPBUTTON_INFO, ["default"] = 1, ["check"] = function () return not FishingBuddy.UseButtonHole(); end, ["checkfail"] = 1 }, { ["name"] = "EnhanceFishingSounds", ["text"] = FishingBuddy.CONFIG_ENHANCESOUNDS_ONOFF, ["tooltip"] = FishingBuddy.CONFIG_ENHANCESOUNDS_INFO, ["default"] = 1 }, } FishingBuddy.ByFishie = nil; FishingBuddy.SortedFishies = nil; local ActionStartTime = 0; local ActionDoubleTime = 0; local ACTIONDOWNWAIT = 0.2; local ACTIONDOUBLEWAIT = 0.4; local SavedAddMessage = nil; FishingBuddy.SavedToggleMinimap = nil; local StartedFishing = nil; local TestingLures = false; local CastingNow = false; local AddingLure = false; local FishingSpellID = nil; local FishingSkillName = nil; local gotSetupDone = false; local playerName = nil; local realmName = nil; FishingBuddy.currentFishies = {}; local DEFAULT_MINIMAP_POSITION = 256; -- Fill in the player name and realm FishingBuddy.SetupNameInfo = function() playerName = UnitName("player"); realmName = GetRealmName(); return playerName, realmName; end FishingBuddy.GetWasWearing = function() if FishingBuddy_Player["WasWearing"] then return FishingBuddy_Player["WasWearing"]; end end FishingBuddy.SetWasWearing = function(outfit) FishingBuddy_Player["WasWearing"] = outfit; end FishingBuddy.GetOutfitItem = function(slotName) if (FishingBuddy_Player["Outfit"]) then return FishingBuddy_Player["Outfit"][slotName]; end end FishingBuddy.GetOutfit = function() return FishingBuddy_Player["Outfit"]; end FishingBuddy.SetOutfit = function(outfit) FishingBuddy_Player["Outfit"] = outfit; end local function GetSetting(setting) if ( not FishingBuddy_Player or not FishingBuddy_Player["Settings"] ) then return; end return FishingBuddy_Player["Settings"][setting]; end FishingBuddy.GetSetting = GetSetting; local function SetSetting(setting, value) FishingBuddy_Player["Settings"][setting] = value; end FishingBuddy.SetSetting = SetSetting; -- handle option keys for enabling casting local key_actions = { [FishingBuddy.KEYS_NONE] = function() return true; end, [FishingBuddy.KEYS_SHIFT] = function() return IsShiftKeyDown(); end, [FishingBuddy.KEYS_CTRL] = function() return IsControlKeyDown(); end, [FishingBuddy.KEYS_ALT] = function() return IsAltKeyDown(); end, } local function CastingKeys() local setting = GetSetting("EasyCastKeys"); if ( key_actions[setting] ) then return key_actions[setting](); else return true; end end -- get our current fishing skill level local lastSkillIndex = nil; FishingBuddy.GetCurrentSkill = function() if ( lastSkillIndex ) then local name, _, _, rank, _, modifier = GetSkillLineInfo(lastSkillIndex); if ( name == FishingBuddy.GetFishingSkillName() )then return rank, modifier; end end local n = GetNumSkillLines(); for i=1,n do local name, _, _, rank, _, modifier = GetSkillLineInfo(i); if ( name == FishingBuddy.GetFishingSkillName() ) then lastSkillIndex = i; return rank, modifier; end end return 0, 0; end FishingBuddy.SetZoneLevel = function(zone, subzone, fishid) local skill, mods = FishingBuddy.GetCurrentSkill(); local fs = FishingBuddy_Info["FishingSkill"]; if ( not fs[zone] ) then fs[zone] = {}; end local skillcheck = skill + mods; if ( skillcheck > 0 ) then if ( not fs[zone][subzone] or skillcheck < fs[zone][subzone] ) then fs[zone][subzone] = skillcheck; end if ( fishie ) then if ( not FishingBuddy_Info["Fishies"][fishid].level or skillcheck < FishingBuddy_Info["Fishies"][fishid].level ) then FishingBuddy_Info["Fishies"][fishid].level = skillcheck; FishingBuddy_Info["Fishies"][fishid].skill = skill; FishingBuddy_Info["Fishies"][fishid].mods = mods; end end end end local OldBindingKey; local function UpdateBindings(onoff) if ( onoff ) then if ( not OldKeyBinding ) then OldKeyBinding = GetBindingKey("TURNORACTION"); if ( OldKeyBinding ) then SetBinding(OldKeyBinding, "FISHINGBUDDY_PERFORMCAST"); else FishingBuddy.UIError(FishingBuddy.TOOMANYFISHERMEN); end end else if ( OldKeyBinding ) then SetBinding(OldKeyBinding, "TURNORACTION"); OldKeyBinding = nil; end end end FishingBuddy.UpdateBindings = UpdateBindings; -- Shamelessly stolen from TackleBox local function IsFishingPole() -- Get the main hand item texture local slot = GetInventorySlotInfo("MainHandSlot"); local itemTexture = GetInventoryItemTexture("player", slot); -- If there is infact an item in the main hand, and it's texture -- that matches the fishing pole texture, then we have a fishing pole if ( itemTexture and string.find(itemTexture, "INV_Fishingpole") ) then local link = GetInventoryItemLink("player", slot); local _, id, _ = FishingBuddy.SplitLink(link); -- Make sure it's not "Nat Pagle's Fish Terminator" return (id ~= 19944); end return false; end FishingBuddy.IsFishingPole = IsFishingPole; -- override the error message method (need an object as the first arg) local function UIError_AddMessage( o, msg, a, r, g, b, hold ) -- If we should be hiding the can't use item error, then do so if ( TestingLures and msg == ERR_CANT_USE_ITEM ) then -- We have the can't use item error, so abort return; end --Call the original local obj = SavedAddMessage.obj; local method = SavedAddMessage.method; return method( obj, msg, a, r, g, b, hold ); end FishingBuddy.AddMessage = UIError_AddMessage; local function HijackCheck() return ( GetSetting("EasyCast") == 1 and CastingKeys() and IsFishingPole() ); end local SavedWFOnMouseUp; local SavedWFOnMouseDown; -- handle mouse up and mouse down in the WorldFrame so that we can steal -- the hardware events to implement 'Easy Cast' -- Thanks to the Cosmos team for figuring this one out -- I didn't realize -- that the mouse handler in the WorldFrame got everything first! local function WF_OnMouseDown() -- Only steal 'right clicks' if ( arg1 == "RightButton" and HijackCheck() ) then FishingBuddy.ActionStartCheck(); end if ( SavedWFOnMouseDown ) then SavedWFOnMouseDown(); end end -- disable click to move if we're fishing local resetClickToMove = false; local function WF_OnMouseUp() local retval; if ( SavedWFOnMouseUp ) then retval = SavedWFOnMouseUp(); end -- Only steal 'right clicks' if ( arg1 == "RightButton" ) then -- we fail if there are multiple modifier keys if ( IsAltKeyDown() and ( IsShiftKeyDown() or IsControlKeyDown() ) ) then return retval; end if ( IsShiftKeyDown() and IsControlKeyDown() ) then return retval; end if ( HijackCheck() ) then FishingBuddy.StopCastingCheck(); elseif ( resetClickToMove ) then -- Re-enable Click-to-Move if we changed it SetCVar("autointeract", "1"); resetClickToMove = nil; end end return retval; end -- Find things in our inventory local function FindItem(id) if ( id ) then local numSlots = 0; -- check each of the bags on the player for bag=0, NUM_BAG_FRAMES do -- get the number of slots in the bag (0 if no bag) numSlots = GetContainerNumSlots(bag); if (numSlots > 0) then -- check each slot in the bag for slot=1, numSlots do local link = GetContainerItemLink (bag,slot); if (link) then local c, i, n = FishingBuddy.SplitLink(link); local check = string.gsub(i, "^(%d+):(%d+):(%d+):(%d+)$", "%1:%2:0:0"); if ( check == id ) then return bag, slot; end end end end end end return nil, nil; end local function SafeHookMethod(object, method, newmethod) local oldValue = object[method]; if ( oldValue ~= getglobal(newmethod) ) then object[method] = newmethod; return true; end return false; end local function SafeHookScript(frame, handlername, newscript) local oldValue = frame:GetScript(handlername); frame:SetScript(handlername, newscript); return oldValue; end -- Something else that should be in a library FishingBuddy.SplitLink = function(link) if ( link ) then local _,_, color, item, name = string.find(link, "|c(%x+)|Hitem:(%d+:%d+:%d+:%d+)|h%[(.-)%]|h|r"); return color, item, name; end end FishingBuddy.SplitFishLink = function(link) if ( link ) then local _,_, color, id, name = string.find(link, "|c(%x+)|Hitem:(%d+):%d+:%d+:%d+|h%[(.-)%]|h|r"); return color, tonumber(id), name; end end -- handle the vagaries of zones and subzones FishingBuddy.GetZoneInfo = function() local zone = GetRealZoneText(); local subzone = GetSubZoneText(); if ( not zone or zone == "" ) then zone = FishingBuddy.UNKNOWN; end if ( not subzone or subzone == "" ) then subzone = zone; end return zone, subzone; end FishingBuddy.AddFishie = function(color, id, name, zone, subzone, texture, quantity, quality) if ( not FishingBuddy_Info["Fishies"][id] ) then FishingBuddy_Info["Fishies"][id] = { }; FishingBuddy_Info["Fishies"][id].name = name; FishingBuddy_Info["Fishies"][id].texture = texture; FishingBuddy_Info["Fishies"][id].quality = quality; if ( color ~= "ffffffff" ) then FishingBuddy_Info["Fishies"][id].color = color; end if ( FishingBuddy.SortedFishies ) then tinsert(FishingBuddy.SortedFishies, { text = name, id = id }); FishingBuddy.FishSort(FishingBuddy.SortedFishies, true); end end if ( not zone ) then zone = FishingBuddy.UNKNOWN; end if ( not subzone ) then subzone = zone; end if ( not FishingBuddy.currentFishies[subzone] ) then FishingBuddy.currentFishies[subzone] = {}; end if ( not FishingBuddy.currentFishies[subzone][id] ) then FishingBuddy.currentFishies[subzone][id] = quantity; else FishingBuddy.currentFishies[subzone][id] = FishingBuddy.currentFishies[subzone][id] + quantity; end if( not FishingBuddy_Info["FishingHoles"][zone] ) then FishingBuddy_Info["FishingHoles"][zone] = { }; tinsert(FishingBuddy.SortedZones, zone); table.sort(FishingBuddy.SortedZones); end if( not FishingBuddy_Info["FishingHoles"][zone][subzone] ) then FishingBuddy_Info["FishingHoles"][zone][subzone] = { }; FishingBuddy.SortedByZone[zone] = {}; tinsert(FishingBuddy.SortedByZone[zone], subzone); table.sort(FishingBuddy.SortedByZone[zone]); tinsert(FishingBuddy.SortedSubZones, subzone); table.sort(FishingBuddy.SortedSubZones); end local fh = FishingBuddy_Info["FishingHoles"][zone]; if ( not fh[subzone][id] ) then fh[subzone][id] = quantity; if ( GetSetting("ShowNewFishies") == 1 ) then FishingBuddy.Print(FishingBuddy.ADDFISHIEMSG, name, subzone); end else fh[subzone][id] = fh[subzone][id] + quantity; end if ( FishingBuddy.ByFishie ) then if ( not FishingBuddy.ByFishie[id] ) then FishingBuddy.ByFishie[id] = {}; end if ( not FishingBuddy.ByFishie[id][subzone] ) then FishingBuddy.ByFishie[id][subzone] = quantity; else FishingBuddy.ByFishie[id][subzone] = FishingBuddy.ByFishie[id][subzone] + quantity; end end FishingBuddy.Locations.DataChanged(zone, subzone, fishie); FishingBuddy.WatchUpdate(); end FishingBuddy.GetFishie = function(fishid) if( FishingBuddy_Info["Fishies"][fishid] ) then return string.format("%d:0:0:0", fishid), FishingBuddy_Info["Fishies"][fishid].texture, FishingBuddy_Info["Fishies"][fishid].color, FishingBuddy_Info["Fishies"][fishid].quantity, FishingBuddy_Info["Fishies"][fishid].quality, FishingBuddy_Info["Fishies"][fishid].name; end end local function ImportFish() local oldShowNewFishies = GetSetting("ShowNewFishies"); SetSetting("ShowNewFishies"); if ( FishInfo2DataSub and FishingBuddy_Info["FishInfo2"] == 0 ) then for toon in FishInfo2DataSub do if ( not string.find(toon, "|User$") ) then for fishie in FishInfo2DataSub[toon] do local texture = FishInfo2DataSub[toon][fishie]["texture"]; local quality = FishInfo2DataSub[toon][fishie]["rarity"]; local fz = FishInfo2DataSub[toon][fishie]["zones"]; local link = FishInfo2DataSub[toon][fishie]["link"]; if ( link ) then local _,_,id = string.find(link, "^(%d+):"); for zone in fz do for subzone in fz[zone] do local quantity = fz[zone][subzone]; FishingBuddy.AddFishie("ffffffff", id, fishie, zone, subzone, texture, quantity, quality) end end end end end end FishingBuddy_Info["FishInfo2"] = 1; FishingBuddy.Print(FishingBuddy.IMPORTMSG, "FishInfo2"); -- elseif ( imppfishinfoDB and FishingBuddy_Info["ImppDBLoaded"] == 0 ) then -- for subzone in imppfishinfoDB do -- for item in imppfishinfoDB[subzone]["itemnames"] do -- local quantity = imppfishinfoDB[subzone]["itemnames"][item].number; -- local texture = imppfishinfoDB[subzone]["itemnames"][item].texture; -- local quality = imppfishinfoDB[subzone]["itemnames"][item].quality; -- FishingBuddy.AddFishie(color, id, name, subzone, texture, item, quantity, quality) -- end -- end -- FishingBuddy_Info["ImppDBLoaded"] = 1; -- FishingBuddy.Print(FishingBuddy.IMPORTMSG, "Impp's fishinfo"); -- elseif ( DataFishDB and FishingBuddy_Info["DataFish"] == 0 ) then -- for fishie in DataFishDB["catches"] do -- for zone in DataFishDB["catches"][fishie]["locnames"] do -- for subzone in DataFishDB["catches"][fishie]["locnames"][zone] do -- local dfl = DataFishDB["locations"][subzone]["itemnames"][fishie]; -- local quantity = dfl["number"]; -- local texture = dfl["texture"]; -- local quality = dfl["quality"]; -- FishingBuddy.AddFishie(color, id, name, zone, subzone, texture, quantity, quality) -- end -- end -- end -- FishingBuddy_Info["DataFish"] = 1; -- FishingBuddy.Print(FishingBuddy.IMPORTMSG, "DataFish"); else FishingBuddy.Message(FishingBuddy.NOIMPORTMSG); end SetSetting("ShowNewFishies", oldShowNewFishies); end local function FindSpellID(thisone) local id = 1; local spellTexture = GetSpellTexture(id, BOOKTYPE_SPELL); while (spellTexture) do if (spellTexture and spellTexture == thisone) then return id; end id = id + 1; spellTexture = GetSpellTexture(id, BOOKTYPE_SPELL); end return nil; end local function GetFishingSpellID() if ( not FishingSpellID or not FishingSkillName) then FishingSpellID = FindSpellID(FishingBuddy.FISHINGTEXTURE); end if ( FishingSpellID and not FishingSkillName ) then FishingSkillName = GetSpellName(FishingSpellID, BOOKTYPE_SPELL); end end FishingBuddy.GetFishingSkillName = function() GetFishingSpellID(); if ( not FishingSkillName ) then return FishingBuddy.FISHINGSKILL; else return FishingSkillName; end end local function InvokeFishing() GetFishingSpellID(); if ( FishingSpellID ) then CastSpell(FishingSpellID, BOOKTYPE_SPELL); end end -- do everything we think is necessary when we start fishing -- even if we didn't do the switch to a fishing pole local function StartFishingMode() if ( not StartedFishing ) then StartedFishing = GetTime(); FishingBuddy.EnhanceFishingSounds(true); FishingBuddy.WatchUpdate(); end end FishingBuddy.StartFishingMode = StartFishingMode; local function StopFishingMode() if ( StartedFishing ) then FishingBuddy.EnhanceFishingSounds(false); FishingBuddy.WatchUpdate(); StartedFishing = nil; end if ( resetClickToMove ) then -- Re-enable Click-to-Move if we changed it SetCVar("autointeract", "1"); resetClickToMove = nil; end end FishingBuddy.StopFishingMode = StopFishingMode; local function FishingMode() if ( IsFishingPole() ) then StartFishingMode(); else StopFishingMode(); end end FishingBuddy.FishingMode = FishingMode; local function OnFishingBobber() if ( GameTooltip:IsVisible() ) then local text = getglobal("GameTooltipTextLeft1"); if ( text ) then text = text:GetText(); -- let a partial match work (for translations) return ( text and string.find(text, FishingBuddy.BOBBER_NAME ) ); end end return false; end -- Easy lures (borrowed from Mugendai's excellent code) local function UpdateLure() -- if the pole has an enchantment, we can assume it's got a lure on it (so far, anyway) if ( ( GetSetting("EasyLures") == 1 ) and not GetWeaponEnchantInfo() ) then -- trap message handler if we haven't already if ( not SavedAddMessage ) then FishingBuddy.TrapUIErrors(); end --Check for a lure in the bags, starting with the highest power one local bag, slot; for lure in FISHINGLURES do --If we find this lure in the bag, then use it bag, slot = FindItem(lure); if (bag and slot) then --We need to temporarily disable the cant use item error, incase this item is too high of a level to use TestingLures = true; --Temporarily disable error message sounds, incase this item is too high of a level to use local soundState = GetCVar("EnableErrorSpeech"); if ( soundState == "1" ) then SetCVar("EnableErrorSpeech", 0); end --Try to use the item UseContainerItem(bag, slot); -- re-enable the can't use item error message TestingLures = false; -- re-enable error message sounds if ( soundState == "1" ) then SetCVar("EnableErrorSpeech", 1); end -- if we have a targeting cursor, then we succesfully used the lure if ( SpellIsTargeting() ) then -- apply the lure to the fishing pole local mainhandslot = GetInventorySlotInfo("MainHandSlot"); PickupInventoryItem(mainhandslot); AddingLure = true; return true; end end end end return false; end FishingBuddy.ActionStartCheck = function() -- Disable Click-to-Move if we're fishing if ( GetCVar("autointeract") == "1" ) then resetClickToMove = true; SetCVar("autointeract", "0"); end -- Don't interrupt putting on a lure, or if we're not fastcasting if ( AddingLure ) then ActionStartTime = 0; else ActionStartTime = GetTime(); end end -- add the double click checking in based on the code is Cosmos FishingBuddy.StopCastingCheck = function() if ( not ActionStartTime ) then ActionStartTime = 0; end if ( not ActionDoubleTime ) then ActionDoubleTime = 0; end local time = GetTime(); local pressTime = time - ActionStartTime; local doubleTime = time - ActionDoubleTime; -- if we're not putting on a lure and the casting modifiers are good if ( not SpellIsTargeting() ) then -- if the click was "short" enough that we're going to treat it -- as a cast if ( ActionStartTime > 0 and ACTIONDOWNWAIT >= pressTime) then -- if we're already casting, enforce double click timing if ( GetSetting("FastCast") ~= 1 and CastingNow and ( ActionDoubleTime == 0 or ACTIONDOUBLEWAIT < doubleTime ) ) then ActionDoubleTime = GetTime(); else ActionDoubleTime = 0; -- rebind the mouse event UpdateBindings(true); end end end end FishingBuddy.PerformCast = function() -- We're stealing the mouse-up hardware event, make sure we exit MouseLook if ( IsMouselooking() ) then MouselookStop(); end -- reset the TURNORACTION binding so that everything else works 'right' UpdateBindings(false); -- put on a lure if we need to if ( not UpdateLure() ) then InvokeFishing(); end end FishingBuddy.TrapUIErrors = function() local temp = {}; temp.obj= UIErrorsFrame; temp.method = UIErrorsFrame["AddMessage"]; if ( SafeHookMethod(UIErrorsFrame, "AddMessage", FishingBuddy.AddMessage) ) then SavedAddMessage = temp; end end FishingBuddy.TrapWorldMouse = function() SavedWFOnMouseUp = SafeHookScript(WorldFrame, "OnMouseUp", WF_OnMouseUp); SavedWFOnMouseDown = SafeHookScript(WorldFrame, "OnMouseDown", WF_OnMouseDown); end -- User interface handling FishingBuddy.Commands = {}; FishingBuddy.Commands[FishingBuddy.SWITCH] = {}; FishingBuddy.Commands[FishingBuddy.SWITCH].func = function() FishingBuddy.OutfitManager.Switch(); return true; end; FishingBuddy.Commands[FishingBuddy.CURRENT] = {}; FishingBuddy.Commands[FishingBuddy.CURRENT].help = FishingBuddy.CURRENT_HELP; FishingBuddy.Commands[FishingBuddy.CURRENT].func = function(what) if ( what and what == FishingBuddy.RESET) then FishingBuddy.currentFishies = {}; FishingMode(); return true; end end; FishingBuddy.Commands[FishingBuddy.IMPORT] = {}; FishingBuddy.Commands[FishingBuddy.IMPORT].help = FishingBuddy.IMPORT_HELP; FishingBuddy.Commands[FishingBuddy.IMPORT].func = function() ImportFish(); return true; end; FishingBuddy.Commands[FishingBuddy.CLEANUP] = {}; FishingBuddy.Commands[FishingBuddy.CLEANUP].help = FishingBuddy.CLEANUP_HELP; FishingBuddy.Commands[FishingBuddy.CLEANUP].func = function(what) local tabs = { "Settings", "Outfit", "WasWearing" }; local rnames = {}; local onames = {}; if ( not what or what == FishingBuddy.CHECK ) then if ( FishingBuddy_Info["Settings"] ) then for name in FishingBuddy_Info["Settings"] do tinsert(onames, name); end end if ( FishingBuddy_Info[realmName] ) then local fs = FishingBuddy_Info[realmName]["Settings"]; if ( fs ) then for name,info in fs do tinsert(rnames, name); end end end if ( next(rnames) or next(onames) ) then if ( next(rnames) ) then FishingBuddy.Print(FishingBuddy.CLEANUP_WILLMSG, realmName, FishingBuddy.EnglishList(rnames)); end if ( next(onames) ) then FishingBuddy.Print(FishingBuddy.CLEANUP_WILLMSG, FishingBuddy.NOREALM, FishingBuddy.EnglishList(onames)); end else FishingBuddy.Message(FishingBuddy.CLEANUP_NONEMSG); end return true; else if ( what == FishingBuddy.NOW ) then if ( FishingBuddy_Info["Settings"] ) then for name in FishingBuddy_Info["Settings"] do tinsert(onames, name); end end if ( FishingBuddy_Info[realmName] ) then local fs = FishingBuddy_Info[realmName]["Settings"]; if ( fs ) then for name,info in fs do tinsert(rnames, name); end end end else if ( FishingBuddy_Info["Settings"] and FishingBuddy_Info["Settings"][what] ) then tinsert(onames, what); elseif ( FishingBuddy_Info[realmName] and FishingBuddy_Info[realmName]["Settings"] and FishingBuddy_Info[realmName]["Settings"][what] ) then tinsert(rnames, what); else FishingBuddy.Print(FishingBuddy.CLEANUP_NOOLDMSG, what); return true; end end if ( next(rnames) or next(onames) ) then if ( next(rnames) ) then for _,name in rnames do for _,tab in tabs do if ( FishingBuddy_Info[realmName] and FishingBuddy_Info[realmName][tab] ) then FishingBuddy_Info[realmName][tab][name] = nil; if ( next(FishingBuddy_Info[realmName][tab]) == nil ) then FishingBuddy_Info[realmName][tab] = nil; end end end end if ( FishingBuddy_Info[realmName] and next(FishingBuddy_Info[realmName]) == nil ) then FishingBuddy_Info[realmName] = nil; end FishingBuddy.Print(FishingBuddy.CLEANUP_DONEMSG, realmName, FishingBuddy.EnglishList(rnames)); end if ( next(onames) ) then for _,name in onames do for _,tab in tabs do if ( FishingBuddy_Info[tab] ) then FishingBuddy_Info[tab][name] = nil; if ( next(FishingBuddy_Info[tab]) ) then FishingBuddy_Info[tab] = nil; end end end end FishingBuddy.Print(FishingBuddy.CLEANUP_DONEMSG, FishingBuddy.NOREALM, FishingBuddy.EnglishList(onames)); end else FishingBuddy.Message(FishingBuddy.CLEANUP_NONEMSG); end return true; end end; local function nextarg(msg, pattern) if ( not msg or not pattern ) then return nil, nil; end local s,e = string.find(msg, pattern); if ( s ) then local word = strsub(msg, s, e); msg = strsub(msg, e+1); return word, msg; end return nil, msg; end FishingBuddy.Command = function(msg) if ( not msg ) then return; end if ( FishingBuddy.IsLoaded() ) then -- collect arguments (whee, lua string manipulation) local cmd; cmd, msg = nextarg(msg, "[%w]+"); -- the empty string gives us no args at all if ( not cmd ) then -- toggle window if ( FishingBuddyFrame:IsVisible() ) then HideUIPanel(FishingBuddyFrame); else ShowUIPanel(FishingBuddyFrame); end elseif ( cmd == FishingBuddy.HELP or cmd == "help" ) then FishingBuddy.Output(FishingBuddy.WINDOW_TITLE); FishingBuddy.PrintHelp(FishingBuddy.HELPMSG); else local command = FishingBuddy.Commands[cmd]; if ( command ) then local args = {}; local goodargs = true; if ( command.args ) then for _,pat in command.args do local w, msg = nextarg(msg, pat); if ( not w ) then goodargs = false; break; end tinsert(args, w); end else local a; while ( msg ) do a, msg = nextarg(msg, "[%w]+"); if ( not a ) then break; end tinsert(args, a); end end if ( not goodargs or not command.func(unpack(args)) ) then if ( command.help ) then FishingBuddy.PrintHelp(command.help); else FishingBuddy.Debug("command failed"); end end else FishingBuddy.Command("help"); end end else FishingBuddy.Error(FishingBuddy.FAILEDINIT); end end FishingBuddy.OnLoad = function() this:RegisterEvent("PLAYER_LOGIN"); this:RegisterEvent("PLAYER_LOGOUT"); this:RegisterEvent("VARIABLES_LOADED"); this:RegisterEvent("ITEM_LOCK_CHANGED"); this:RegisterEvent("LOOT_OPENED"); this:RegisterEvent("ZONE_CHANGED"); this:RegisterEvent("MINIMAP_ZONE_CHANGED"); this:RegisterEvent("SPELLS_CHANGED"); this:RegisterEvent("SPELLCAST_CHANNEL_START"); this:RegisterEvent("SPELLCAST_CHANNEL_STOP"); this:RegisterEvent("SPELLCAST_START"); this:RegisterEvent("SPELLCAST_STOP"); this:RegisterEvent("SPELLCAST_INTERRUPTED"); this:RegisterEvent("SPELLCAST_FAILED"); this:RegisterEvent("SKILL_LINES_CHANGED"); -- Set up command SlashCmdList["fishingbuddy"] = FishingBuddy.Command; SLASH_fishingbuddy1 = "/fishingbuddy"; SLASH_fishingbuddy2 = "/fb"; FishingBuddy.Output(FishingBuddy.WINDOW_TITLE.." loaded"); end FishingBuddy.OnEvent = function() local needUpdate = false; if ( event == "VARIABLES_LOADED" ) then FishingBuddy.Initialize(); elseif ( event == "PLAYER_LOGIN" ) then -- set up outfit stuff FishingBuddy.OutfitManager.Initialize(); FishingMode(); elseif ( event == "PLAYER_LOGOUT" ) then -- reset the fishing sounds, if we need to StopFishingMode(); FishingBuddy.SavePlayerInfo(); elseif ( event == "ITEM_LOCK_CHANGED" ) then FishingMode(); elseif ( event == "LOOT_OPENED" ) then if ( IsFishingLoot()) then local zone, subzone = FishingBuddy.GetZoneInfo(); for index = 1, GetNumLootItems(), 1 do if (LootSlotIsItem(index)) then local texture, fishie, quantity, quality = GetLootSlotInfo(index); local link = GetLootSlotLink(index); local color, id, name = FishingBuddy.SplitFishLink(link); FishingBuddy.AddFishie(color, id, name, zone, subzone, texture, quantity, quality); if ( FishingBuddy.AddTracking ) then FishingBuddy.AddTracking(id, name); end FishingBuddy.SetZoneLevel(zone, subzone, id); end end end elseif ( event == "ZONE_CHANGED" or event == "MINIMAP_ZONE_CHANGED" ) then if ( not FishingBuddy.IsLoaded() ) then return; end FishingBuddy.currentFishies = {}; needUpdate = true; elseif ( event == "SKILL_LINES_CHANGED" ) then if ( GetSetting("WatchCurrentSkill") == 1 ) then needUpdate = true; end elseif ( event == "SPELLS_CHANGED" ) then -- Fishing might have moved, go look again FishingSpellID = nil; else -- Mugendai is one sharp cookie (shamelessly stealing from TackleBox again) -- Keep up with whether or not we are casting if ( event == "SPELLCAST_CHANNEL_START" ) then CastingNow = true; elseif ( event == "SPELLCAST_CHANNEL_STOP" ) then CastingNow = false; else -- Keep up with whether we are adding a lure (or casting a normal spell) or not if ( event == "SPELLCAST_START" ) then -- AddingLure = true; elseif ( event == "SPELLCAST_STOP" ) then if ( AddingLure ) then AddingLure = false; -- update the skill line if we have one if ( GetSetting("WatchCurrentSkill") == 1 ) then needUpdate = true; end end elseif ( ( event == "SPELLCAST_INTERRUPTED" ) or ( event == "SPELLCAST_FAILED" ) ) then AddingLure = false; end end end FishingBuddy.Extravaganza.IsTime(true); if ( needUpdate ) then FishingBuddy.WatchUpdate(); end end FishingBuddy.PrintHelp = function(tab) if ( type(tab) == "table" ) then for _,line in tab do FishingBuddy.PrintHelp(line); end else FishingBuddy.Output(tab); end end FishingBuddy["EFSV"] = {}; FishingBuddy["EFSV"]["MusicVolume"] = tonumber(GetCVar("MusicVolume")); FishingBuddy["EFSV"]["AmbienceVolume"] = tonumber(GetCVar("AmbienceVolume")); FishingBuddy["EFSV"]["SoundVolume"] =tonumber(GetCVar("SoundVolume")); local SoundWasEnhanced; FishingBuddy.EnhanceFishingSounds = function(turniton) if ( GetSetting("EnhanceFishingSounds") == 1 ) then if ( turniton ) then -- collect the current value FishingBuddy["EFSV"]["MusicVolume"] = tonumber(GetCVar("MusicVolume")); FishingBuddy["EFSV"]["AmbienceVolume"] = tonumber(GetCVar("AmbienceVolume")); FishingBuddy["EFSV"]["SoundVolume"] =tonumber(GetCVar("SoundVolume")); -- turn 'em off! for setting in FishingBuddy["EFSV"] do SetCVar(setting, GetSetting("EnhanceSound"..setting)); end SoundWasEnhanced = true; else if ( SoundWasEnhanced ) then for setting, value in FishingBuddy["EFSV"] do SetCVar(setting, value); end SoundWasEnhanced = false; end end end end -- Drop-down menu support FishingBuddy.ToggleSetting = function(setting) local value = GetSetting(setting); if ( not value ) then value = 0; end SetSetting(setting, 1 - value); FishingBuddy.WatchUpdate(); FishingBuddy.UpdateMinimap(); end -- save some memory by keeping one copy of each one local ToggleFunctions = {}; -- let's use closures local function MakeToggle(name) if ( not ToggleFunctions[name] ) then local n = name; ToggleFunctions[name] = function() FishingBuddy.ToggleSetting(n) end; end return ToggleFunctions[name]; end FishingBuddy.MakeDropDown = function(switchItem, switchSetting) local info; -- If no outfit frame, we can't switch outfits... if ( FishingBuddy.OutfitManager.HasManager() ) then info = {}; info.text = switchItem; info.func = MakeToggle(switchSetting); info.checked = (GetSetting(switchSetting) == 1); info.keepShownOnClick = 1; UIDropDownMenu_AddButton(info); info = {}; info.disabled = 1; UIDropDownMenu_AddButton(info); end for _, option in FishingBuddy.OPTIONS do local addthis = true; if ( option.check ) then addthis = option.check(); end if ( addthis ) then info = {}; info.text = option.text; info.func = MakeToggle(option.name); info.checked = (GetSetting(option.name) == 1); info.keepShownOnClick = 1; UIDropDownMenu_AddButton(info); end end end -- utility functions FishingBuddy.AddTooltip = function(text, r, g, b) if ( text ) then if ( type(text) == "table" ) then for _,l in text do FishingBuddy.AddTooltip(l.text, l.r, l.g, l.b); end else GameTooltip:AddLine(text, r, g, b); end end end FishingBuddy.ChatLink = function(item, name, color) if( item and name and ChatFrameEditBox:IsVisible() ) then if not color then color = FishingBuddy.Colors.WHITE; end local link = "|c"..color.."|Hitem:"..item.."|h["..name.."]|h|r"; ChatFrameEditBox:Insert(link); end end FishingBuddy.FishSort = function(tab, forcename) if ( forcename or GetSetting("SortByPercent") == 0 ) then table.sort(tab, function(a,b) return a.text and b.text and a.text