├── README.md ├── core.lua ├── frames.lua ├── libs ├── AceAddon-2.0 │ └── AceAddon-2.0.lua ├── AceConsole-2.0 │ └── AceConsole-2.0.lua ├── AceDebug-2.0 │ └── AceDebug-2.0.lua ├── AceEvent-2.0 │ └── AceEvent-2.0.lua ├── AceHook-2.1 │ └── AceHook-2.1.lua ├── AceLibrary │ └── AceLibrary.lua ├── AceLocale-2.2 │ └── AceLocale-2.2.lua ├── AceOO-2.0 │ └── AceOO-2.0.lua ├── Banzai-1.0 │ └── Banzai-1.0.lua ├── Compost-2.0 │ └── Compost-2.0.lua ├── Deformat-2.0 │ └── Deformat-2.0.lua ├── Gratuity-2.0 │ └── Gratuity-2.0.lua ├── HealComm-1.0 │ └── HealComm-1.0.lua ├── ItemBonusLib-1.0 │ ├── ItemBonusLib-1.0.lua │ └── Locales │ │ ├── deDE.lua │ │ ├── enUS.lua │ │ ├── frFR.lua │ │ └── ruRU.lua └── RosterLib-2.0 │ └── RosterLib-2.0.lua ├── localization.lua ├── mapsizes.lua ├── media ├── GridGradient.tga ├── Striped.tga ├── borderartwork.tga ├── res.tga └── screenshot.jpg ├── menus.lua ├── notgrid.toc ├── options.lua └── proximity.lua /README.md: -------------------------------------------------------------------------------- 1 | # NotGrid 2 | NotGrid is a party and raid frame addon for Vanilla World of Warcraft (1.12.1). While heavily based off of the original addon Grid, it both lacks some Grid features as well as adds new ones. It supports Clique keybinds & macros, Lazyspell, healcomm, eight buff/debuff icons around the unit frame, low mana & aggro warning, proximity checking, pets, and a simple config menu for general resizing/coloring options. 3 | 4 | ![Screenshot](media/screenshot.jpg) 5 | 6 | ## Usage 7 | Use */notgrid* or */ng* to show the config menu. 8 | Use */notgrid grid* to generate a style similar to the original grid. 9 | Use */notgrid reset* to restore the default settings. 10 | Use / for separating multiple Buffs/Debuffs to track on one icon. 11 | Use */ngcast spellname(Rank X)* in macros for mouseover casting. 12 | 13 | ## Optional Dependencies 14 | Clique: Enables click-casting on your unit frames. 15 | LazySpell: Enables Clique and /ngcast auto spell rank scaling depending on unit health deficit. 16 | 17 | ## Additional Note 18 | If you're having issues with the frame borders/edges being un-uniformly sized or appearing clipped by the healthbar make sure to have a proper [UI scale](http://wow.gamepedia.com/UI_Scale) set. 19 | TLDR: If you play with a 1920x1080 resolution, the correct UI scale would be 768/1080 = 0.7111..., and you would set that by typing */console UIScale 0.7111111111* in the chat. 20 | -------------------------------------------------------------------------------- /core.lua: -------------------------------------------------------------------------------- 1 | local L = AceLibrary("AceLocale-2.2"):new("NotGrid") 2 | NotGrid = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0") 3 | NotGridOptions = {} -- After the addon is fully initialized WoW will fill this up with its saved variables if any 4 | 5 | function NotGrid:OnInitialize() 6 | self.HealComm = AceLibrary("HealComm-1.0") 7 | self.Banzai = AceLibrary("Banzai-1.0") -- cycles through roster and checks targetof..unitds and targetoftargetof..unitids and reports aggro/loss depending 8 | self.Gratuity = AceLibrary("Gratuity-2.0") -- for aura handling 9 | self.RosterLib = AceLibrary("RosterLib-2.0") 10 | self.Compost = AceLibrary("Compost-2.0") 11 | self.UnitFrames = {} 12 | -- 13 | self.IdenticalUnits = {} -- will hold pairs of party/player/raidids that are the same effective unit. For use with rosterlib & healcomm stuff 14 | --proximity stuff 15 | self.ProximityVars = {} -- will hold vars related to proximity handling. Mostly world map stuff 16 | self:GetFortyYardSpell() -- queries the player's action bars for a 40 yard spell to use in proximity checking 17 | self:GetMapSizes() -- populate ProximityVars with mapsizes of server 18 | -- 19 | self:CreateFrames() 20 | end 21 | 22 | function NotGrid:OnEnable() 23 | self.o = NotGridOptions -- Need to wait for addon to be fully initialized and saved variables loaded before I set this 24 | self:SetDefaultOptions() -- if NotGridOptions is empty(no saved variables) this will fill it up with defaults 25 | self:DoDropDown() 26 | self:ConfigUnitFrames() 27 | --proximity stuff 28 | self:RegisterEvent("ACTIONBAR_SLOT_CHANGED", "GetFortyYardSpell") 29 | for key in L.CombatEvents do 30 | self:RegisterEvent(key, "CombatEventHandle") 31 | end 32 | -- 33 | if Clique and self.o.cliquehook then 34 | Clique.CastSpell = NotGrid.CastHandle -- lazyspell uses _ as a prefix to load last so it will hook into my hook. 35 | end 36 | -- 37 | self:RegisterEvent("PLAYER_ENTERING_WORLD") 38 | self:RegisterEvent("CHAT_MSG_ADDON") 39 | self:RegisterEvent("ZONE_CHANGED_NEW_AREA","UpdateProximityMapVars") 40 | self:RegisterEvent("PARTY_MEMBERS_CHANGED","BlizzFrameHandler") 41 | self:RegisterEvent("RAID_ROSTER_UPDATE","BlizzFrameHandler") 42 | self:RegisterEvent("UNIT_PET","BlizzFrameHandler") 43 | --RosterLib 44 | self:RegisterEvent("RosterLib_RosterChanged") 45 | self:RegisterEvent("RosterLib_UnitChanged") 46 | --Banzai/Aggro 47 | self:RegisterEvent("Banzai_UnitGainedAggro","UNIT_BORDER") -- sends unitid to UNIT_BORDER 48 | self:RegisterEvent("Banzai_UnitLostAggro","UNIT_BORDER") 49 | --Healcomm 50 | self:RegisterEvent("HealComm_Healupdate","HealCommHandler") 51 | self:RegisterEvent("HealComm_Ressupdate","HealCommHandler") 52 | --Proximity 53 | self:RegisterEvent("NG_UNIT_PROXIMITY","UNIT_PROXIMITY") 54 | self:ScheduleRepeatingEvent("NG_UNIT_PROXIMITY", self.o.proximityrate) 55 | end 56 | 57 | --------------- 58 | -- UNIT_MAIN -- Handles the healthbar, healthtext, healcommbar, healcommtext, ressurection, nametext, classcolor.. 59 | --------------- 60 | 61 | function NotGrid:UNIT_MAIN(unitid) 62 | local o = self.o 63 | local f = self.UnitFrames[unitid] 64 | if o.configmode then 65 | unitid = "player" 66 | end 67 | 68 | if f and UnitExists(unitid) then 69 | local name = UnitName(unitid) 70 | local shortname = string.sub(name, 1, o.namelength) 71 | local _,class = UnitClass(unitid) 72 | local powertype = UnitPowerType(unitid) 73 | local pcolor = ManaBarColor[powertype] 74 | local color = {} 75 | 76 | if o.configmode then 77 | local c = {"WARRIOR","PALADIN","HUNTER","ROGUE","PRIEST","SHAMAN","MAGE","WARLOCK","DRUID"} 78 | local id = string.sub(f.unit, -1) 79 | id = tonumber(id) 80 | if id == 0 then id = 1 end 81 | if id == 1 then 82 | pcolor = ManaBarColor[1] 83 | elseif id == 4 then 84 | pcolor = ManaBarColor[3] 85 | else 86 | pcolor = ManaBarColor[0] 87 | end 88 | class = c[id] 89 | end 90 | 91 | if f.pet and o.usepetcolor then 92 | color.r,color.g,color.b = unpack(o.petcolor) 93 | elseif class and class == "SHAMAN" and o.useshamancolor then 94 | color = {r=0.14,g=0.35,b=1} 95 | elseif class then 96 | color = RAID_CLASS_COLORS[class] 97 | else 98 | color = {r=1,g=0,b=1} 99 | end 100 | 101 | --update some stuff 102 | f.name = name 103 | --handle coloring text 104 | if o.colorunithealthbarbyclass then 105 | f.healthbar:SetStatusBarColor(color.r, color.g, color.b, o.unithealthbarcolor[4]) 106 | end 107 | if o.colorunitnamehealthbyclass then 108 | f.namehealthtext:SetTextColor(color.r, color.g, color.b, o.unitnamehealthtextcolor[4]) 109 | end 110 | if o.colorunithealthbarbgbyclass then 111 | f.healthbar.bgtex:SetVertexColor(color.r, color.g, color.b) 112 | end 113 | 114 | f.powerbar:SetStatusBarColor(pcolor.r, pcolor.g, pcolor.b) 115 | if o.colorpowerbarbgbytype then 116 | f.powerbar.bgtex:SetVertexColor(pcolor.r, pcolor.g, pcolor.b) 117 | end 118 | 119 | if UnitIsConnected(unitid) then 120 | local healamount, currhealth, maxhealth, deficit, healtext, currpower, maxpower 121 | if o.configmode then 122 | currhealth = UnitHealth(unitid)/2 123 | maxhealth = UnitHealthMax(unitid) 124 | deficit = maxhealth - currhealth 125 | currpower = UnitManaMax(unitid)/2 126 | maxpower = UnitManaMax(unitid) 127 | healamount = maxhealth/4 128 | else 129 | currhealth = UnitHealth(unitid) 130 | maxhealth = UnitHealthMax(unitid) 131 | deficit = maxhealth - currhealth 132 | currpower = UnitMana(unitid) 133 | maxpower = UnitManaMax(unitid) 134 | healamount = self.HealComm:getHeal(name) 135 | end 136 | 137 | if healamount > 999 then 138 | healtext = string.format("+%.1fk", healamount/1000.0) 139 | else 140 | healtext = string.format("+%d", healamount) 141 | end 142 | 143 | f.healthbar:SetMinMaxValues(0, maxhealth) 144 | f.healthbar:SetValue(currhealth) 145 | 146 | f.powerbar:SetMinMaxValues(0, maxpower) 147 | f.powerbar:SetValue(currpower) 148 | 149 | if UnitIsDead(unitid) then 150 | self:UnitHealthZero(f, L["Dead"], shortname) 151 | elseif UnitIsGhost(unitid) or (deficit >= maxhealth) then -- we can't detect unitisghost if he's not in range so we do the additional conditional. It won't false report for "dead" because that's checked first. Still a lot of false reports. In BGs. 152 | self:UnitHealthZero(f, L["Ghost"], shortname) 153 | elseif currhealth/maxhealth*100 <= self.o.healththreshhold then 154 | local deficittext 155 | if deficit > 999 then 156 | deficittext = string.format("-%.1fk", deficit/1000.0) 157 | else 158 | deficittext = string.format("-%d", deficit) 159 | end 160 | f.namehealthtext:SetText(deficittext) 161 | else 162 | f.namehealthtext:SetText(shortname) 163 | end 164 | 165 | if healamount > 0 then 166 | if o.showhealcommbar then 167 | self:SetIncHealFrame(f, healamount, currhealth, maxhealth) 168 | end 169 | if o.showhealcommtext then 170 | f.healcommtext:SetText(healtext) 171 | f.healcommtext:Show() 172 | end 173 | else 174 | f.incheal:SetBackdropColor(0,0,0,0) -- instead of hiding the frame, which is parent to healthtext&inchealtext, I set its opacity to 0 175 | f.healcommtext:Hide() 176 | end 177 | 178 | if self.HealComm:UnitisResurrecting(name) then 179 | f.incres:Show() 180 | else 181 | f.incres:Hide() 182 | end 183 | else 184 | self:UnitHealthZero(f, "Offline", shortname) 185 | end 186 | end 187 | end 188 | 189 | function NotGrid:UnitHealthZero(f, state, shortname) 190 | f.namehealthtext:SetText(shortname.."\n"..state) 191 | f.incheal:SetBackdropColor(0,0,0,0) -- instead of hiding the frame, which is parent to healthtext&inchealtext, I set its opacity to 0 192 | f.healthbar:SetMinMaxValues(0, 1) 193 | f.healthbar:SetValue(0) 194 | f.powerbar:SetMinMaxValues(0, 1) 195 | f.powerbar:SetValue(0) 196 | f.healcommtext:Hide() 197 | end 198 | 199 | function NotGrid:SetIncHealFrame(f, healamount, currhealth, maxhealth) -- well this was easier than I was expecting it to be 200 | local o = self.o 201 | if o.unithealthorientation == 1 then -- I could rewrite these so its less copy paste but leaving it for now 202 | local modifier = maxhealth/o.unitheight -- get the modifer to convert health amounts to pixels based on set height 203 | local healheight = healamount/modifier 204 | local currheight = currhealth/modifier 205 | local maxheight = o.unitheight-currheight 206 | if maxheight == 0 then return end -- if the max height would equal to be 0 then SetHeight() function won't work so I jsut stop this function now 207 | if healheight >= maxheight then healheight = maxheight end 208 | f.incheal:SetHeight(healheight) 209 | f.incheal:ClearAllPoints() 210 | f.incheal:SetPoint("BOTTOM",0,currheight) 211 | else 212 | local modifier = maxhealth/o.unitwidth 213 | local healwidth = healamount/modifier 214 | local currwidth = currhealth/modifier 215 | local maxwidth = o.unitwidth-currwidth 216 | if maxwidth == 0 then return end 217 | if healwidth >= maxwidth then healwidth = maxwidth end 218 | f.incheal:SetWidth(healwidth) 219 | f.incheal:ClearAllPoints() 220 | f.incheal:SetPoint("LEFT",currwidth,0) 221 | end 222 | local color = o.unithealcommbarcolor 223 | f.incheal:SetBackdropColor(color[1],color[2],color[3],color[4]) -- instead of hide/show I set opacity. Note that I can't use SetAlpha cause it will hide the child elements 224 | end 225 | 226 | --------------- 227 | -- UNIT_AURA -- 228 | --------------- 229 | 230 | function NotGrid:UNIT_AURA(unitid) 231 | local o = self.o 232 | local f = self.UnitFrames[unitid] 233 | 234 | local auratable = self.Compost:Acquire() -- I only care about buffname for buffs -- reset every time 235 | 236 | if f and UnitExists(unitid) then 237 | --get buff info -- loop through every buff and adds info to table 238 | local bi = 1 239 | while (UnitBuff(unitid,bi) ~= nil) do 240 | self.Gratuity:SetUnitBuff(unitid,bi) 241 | local buffname = self.Gratuity:GetLine(1) 242 | if buffname then 243 | auratable[buffname] = true 244 | end 245 | bi = bi + 1; 246 | end 247 | 248 | --get debuff info -- same as above 249 | local di = 1 250 | while (UnitDebuff(unitid,di) ~= nil) do 251 | self.Gratuity:SetUnitDebuff(unitid,di) 252 | local debuffname = self.Gratuity:GetLine(1) 253 | local _, _, spelltype = UnitDebuff(unitid,di) -- texture, applications, type 254 | if debuffname then 255 | auratable[debuffname] = true 256 | end 257 | if spelltype then 258 | auratable[spelltype] = true 259 | end 260 | di = di + 1; 261 | end 262 | 263 | for i=1,8 do 264 | local f = f.healthbar["trackingicon"..i] 265 | if self:CheckAura(i,auratable) then 266 | if self.o["trackingicon"..i.."invert"] then 267 | f:Hide() 268 | else 269 | f:Show() 270 | end 271 | else 272 | if self.o["trackingicon"..i.."invert"] then 273 | f:Show() 274 | else 275 | f:Hide() 276 | end 277 | end 278 | end 279 | end 280 | self.Compost:Reclaim(auratable) 281 | end 282 | 283 | function NotGrid:CheckAura(i, auratable) 284 | for _,text in self.o["trackingicon"..i] do 285 | if auratable[text] then 286 | return true 287 | end 288 | end 289 | end 290 | 291 | ----------------- 292 | -- UNIT_BORDER -- 293 | ----------------- 294 | 295 | function NotGrid:UNIT_BORDER(unitid) 296 | local o = self.o 297 | local f = self.UnitFrames[unitid] 298 | if f and UnitExists(unitid) then 299 | local name = UnitName(unitid) 300 | local targetname = UnitName("Target") -- could get erronous with pets 301 | local currmana = UnitMana(unitid) 302 | local maxmana = UnitManaMax(unitid) 303 | if o.tracktarget and targetname and targetname == name then 304 | f.border:SetBackdropBorderColor(unpack(o.targetcolor)) 305 | f.border.middleart:SetVertexColor(unpack(o.targetcolor)) 306 | elseif o.trackaggro and self.Banzai:GetUnitAggroByUnitId(unitid) then 307 | f.border:SetBackdropBorderColor(unpack(o.aggrowarningcolor)) 308 | f.border.middleart:SetVertexColor(unpack(o.aggrowarningcolor)) 309 | elseif o.trackmana and UnitPowerType(unitid) == 0 and currmana/maxmana*100 < o.manathreshhold and not UnitIsDeadOrGhost(unitid) then 310 | f.border:SetBackdropBorderColor(unpack(o.manawarningcolor)) 311 | f.border.middleart:SetVertexColor(unpack(o.manawarningcolor)) 312 | else 313 | f.border:SetBackdropBorderColor(unpack(o.unitbordercolor)) 314 | f.border.middleart:SetVertexColor(unpack(o.unitbordercolor)) 315 | end 316 | end 317 | end 318 | 319 | ------------------- 320 | -- On Unit Click -- 321 | ------------------- 322 | 323 | function NotGrid:ClickHandle(button) 324 | if button == "RightButton" and SpellIsTargeting() then 325 | SpellStopTargeting() 326 | return 327 | end 328 | if button == "LeftButton" then 329 | if SpellIsTargeting() then 330 | SpellTargetUnit(this.unit) 331 | elseif CursorHasItem() then 332 | DropItemOnUnit(this.unit) 333 | else 334 | TargetUnit(this.unit) 335 | end 336 | else --Thanks Luna :^) 337 | local name = UnitName(this.unit) 338 | local id = string.sub(this.unit,5) 339 | local unit = this.unit 340 | local menuFrame = FriendsDropDown 341 | menuFrame.displayMode = "MENU" 342 | menuFrame.initialize = function() UnitPopup_ShowMenu(getglobal(UIDROPDOWNMENU_OPEN_MENU), "PARTY", unit, name, id) end 343 | ToggleDropDownMenu(1, nil, FriendsDropDown, "cursor") 344 | end 345 | end 346 | 347 | --------------------- 348 | -- Mousover Mimick -- 349 | --------------------- 350 | 351 | SLASH_NOTGRIDCAST1 = "/ngcast" 352 | function SlashCmdList.NOTGRIDCAST(spell, editbox) 353 | local unitid = GetMouseFocus().unit 354 | if LazySpell and unitid then -- lazyspell will hook into my clique hook so we only need to apply it to ngcast 355 | if LazySpell.ValidateSpell then -- use convenient function from newer version 356 | spell = LazySpell:ValidateSpell(spell, unitid) 357 | else -- go through the original version 358 | local lsSpell,lsRank = LazySpell:ExtractSpell(spell) 359 | if NotGrid.HealComm.Spells[lsSpell] and lsRank == 1 then 360 | local lsRank = LazySpell:CalculateRank(lsSpell, unitid) 361 | spell = lsSpell.."(Rank "..lsRank..")" 362 | end 363 | end 364 | end 365 | NotGrid:CastHandle(spell,unitid) 366 | end 367 | 368 | --------------------- 369 | -- Spell Cast Hook -- 370 | --------------------- 371 | 372 | function NotGrid:CastHandle(spell, unitid) 373 | if unitid == "target" then -- prioritize healcomm functionality above proximity checks 374 | CastSpellByName(spell) 375 | if SpellIsTargeting() then 376 | SpellStopTargeting() 377 | end 378 | return 379 | end 380 | local LastTarget = UnitName("target") --used as boolean before using targetlasttarget 381 | ClearTarget() 382 | CastSpellByName(spell) 383 | NotGrid:SpellCanTarget() --check proximity on all roster members while the spell is queued up, have to specify NotGrid because it will be called by Clique if hooked 384 | if unitid and UnitExists(unitid) and SpellIsTargeting() and SpellCanTargetUnit(unitid) then -- then come back to our own func and see if they can cast on the unit they wanted to cast on 385 | SpellTargetUnit(unitid) -- if they can, cast on them 386 | elseif SpellCanTargetUnit("mouseover") then -- for casting outside unitframes .. does this affect clique in anyway? 387 | SpellTargetUnit("mouseover") 388 | end 389 | if SpellIsTargeting() then -- we queued up the spell but previous checks couldnt cast it on anyone 390 | SpellStopTargeting() -- stop targetting 391 | end 392 | if LastTarget then -- remember, use it as a boolean. 393 | TargetLastTarget() -- and finally, if they actually had an old target, then target it 394 | end 395 | end 396 | 397 | 398 | ---------------------------------- 399 | -- Miscellaneous Event Handling -- 400 | ---------------------------------- 401 | 402 | -- Healcomm 403 | 404 | function NotGrid:HealCommHandler(name) -- be nice if it sent us the unitid instead 405 | local unitid = self.RosterLib:GetUnitIDFromName(name) 406 | self:UNIT_MAIN(unitid) 407 | if self.IdenticalUnits[unitid] then 408 | self:UNIT_MAIN(self.IdenticalUnits[unitid]) 409 | end 410 | end 411 | 412 | -- Roster 413 | 414 | --blizz roster events fire for all sorts of frivilous(in our case) reasons creating unnecessary updates 415 | --rosterlib cycles through units and sends ones that have changed, with what has changed, and we filter it from there as to whether we want to do anything with our frames 416 | function NotGrid:RosterLib_RosterChanged(updatedUnits) 417 | for _,val in updatedUnits do 418 | if not (val.unitid and string.find(val.unitid, "raidpet")) and not (val.oldunitid and string.find(val.oldunitid, "raidpet")) then -- if not raidpet, because we have no unitframes for them 419 | self:GetIdenticalUnits() 420 | self:PositionFrames() 421 | break -- break out of the loop after finding at least one unit we have a frame for 422 | end 423 | end 424 | end 425 | 426 | function NotGrid:GetIdenticalUnits() -- party/raid pets? 427 | if GetNumRaidMembers() > 0 then 428 | self.Compost:Reclaim(self.IdenticalUnits) 429 | self.IdenticalUnits = self.Compost:Acquire() 430 | local playername = UnitName("player") 431 | for i=1,40 do 432 | if UnitExists("raid"..i) then 433 | local raidid = "raid"..i 434 | local raidname = UnitName(raidid) 435 | if playername == raidname then 436 | self.IdenticalUnits[raidid] = "player" 437 | self.IdenticalUnits["player"] = raidid 438 | end 439 | for i=1,4 do 440 | if UnitExists("party"..i) then 441 | local partyid = "party"..i 442 | local partyname = UnitName(partyid) 443 | if partyname == raidname then 444 | self.IdenticalUnits[raidid] = partyid -- store them both as their own keys referencing eachother 445 | self.IdenticalUnits[partyid] = raidid 446 | end 447 | end 448 | end 449 | end 450 | end 451 | elseif next(self.IdenticalUnits) then -- if theres data in the table, but we're not in raid, then wipe the table 452 | self.Compost:Reclaim(self.IdenticalUnits) 453 | self.IdenticalUnits = self.Compost:Acquire() 454 | end 455 | end 456 | 457 | function NotGrid:RosterLib_UnitChanged(unitid, name, class, subgroup, rank, oldname, oldunitid, oldclass, uldsubgroup, oldrank) 458 | if unitid and self.UnitFrames[unitid] then 459 | self:UNIT_MAIN(unitid) 460 | self:UNIT_BORDER(unitid) 461 | self:UNIT_AURA(unitid) 462 | if self.IdenticalUnits[unitid] then 463 | self:UNIT_MAIN(self.IdenticalUnits[unitid]) 464 | self:UNIT_BORDER(self.IdenticalUnits[unitid]) 465 | self:UNIT_AURA(self.IdenticalUnits[unitid]) 466 | end 467 | end 468 | end 469 | 470 | 471 | -- Blizz Events 472 | 473 | function NotGrid:PLAYER_ENTERING_WORLD() -- when they login,reloadui,or zone in/out of instances 474 | if self.o.versionchecking then 475 | --SendAddonMessage("NotGrid", self.o.version, "GUILD") 476 | --SendAddonMessage("NotGrid", self.o.version, "BATTLEGROUND") 477 | if GetNumRaidMembers() > 0 then 478 | SendAddonMessage("NotGrid", self.o.version, "RAID") 479 | elseif GetNumPartyMembers() > 0 then 480 | SendAddonMessage("NotGrid", self.o.version, "PARTY") 481 | end 482 | end 483 | self:UpdateProximityMapVars() -- zoning into an instance won't trigger a zonechange event if the outdoors name is the same name as the indoors. This ensures the vars update. 484 | self:BlizzFrameHandler() 485 | end 486 | 487 | function NotGrid:CHAT_MSG_ADDON() 488 | if arg1 == "NotGrid" and self.o.versionchecking then 489 | if tonumber(arg2) > self.o.version and not self.versionalreadyshown then 490 | DEFAULT_CHAT_FRAME:AddMessage("|cff0ccca6NotGrid:|r A newer version may be available.") 491 | self.versionalreadyshown = true 492 | end 493 | end 494 | end 495 | 496 | --have to handle the blizzframes seperately because rosterlib only fires if a member changed, wheras PARTY_MEMBERS_CHANGED fires for loot and other reasons as well 497 | function NotGrid:BlizzFrameHandler() -- called by PLAYER_ENTERING_WORLD,PARTY_MEMBER_CHANGED,RAID_ROSTER_UPDATE,UNIT_PET,and NotGridOptionChange() 498 | for i=1,GetNumPartyMembers() do -- this isn't perfect because, for example, if partycount were at 0 it just wouldn't run and wouldn't hide any remaining frames. But blizz's code handles hiding it natively on member leave so I won't worry about it. 499 | if self.o.showblizzframes then 500 | getglobal("PartyMemberFrame"..i):Show(); 501 | else 502 | getglobal("PartyMemberFrame"..i):Hide(); 503 | end 504 | end 505 | end 506 | -------------------------------------------------------------------------------- /libs/AceAddon-2.0/AceAddon-2.0.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnwl/NotGrid/466d1040a5dd53c87fa2c3b268d2e3e0bb13d71f/libs/AceAddon-2.0/AceAddon-2.0.lua -------------------------------------------------------------------------------- /libs/AceDebug-2.0/AceDebug-2.0.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Name: AceDebug-2.0 3 | Revision: $Rev: 99999 $ 4 | Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) 5 | Inspired By: Ace 1.x by Turan (turan@gryphon.com) 6 | Website: http://www.wowace.com/ 7 | Documentation: http://www.wowace.com/index.php/AceDebug-2.0 8 | SVN: http://svn.wowace.com/root/trunk/Ace2/AceDebug-2.0 9 | Description: Mixin to allow for simple debugging capabilities. 10 | Dependencies: AceLibrary, AceOO-2.0 11 | ]] 12 | 13 | local MAJOR_VERSION = "AceDebug-2.0" 14 | local MINOR_VERSION = "$Revision: 99999 $" 15 | 16 | if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end 17 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end 18 | 19 | if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check 20 | if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end 21 | 22 | local DEBUGGING, TOGGLE_DEBUGGING 23 | 24 | if GetLocale() == "frFR" then 25 | DEBUGGING = "D\195\169boguage" 26 | TOGGLE_DEBUGGING = "Activer/d\195\169sactiver le d\195\169boguage" 27 | elseif GetLocale() == "deDE" then 28 | DEBUGGING = "Debuggen" 29 | TOGGLE_DEBUGGING = "Aktiviert/Deaktiviert Debugging" 30 | elseif GetLocale() == "koKR" then 31 | DEBUGGING = "디버깅" 32 | TOGGLE_DEBUGGING = "디버깅 기능 사용함/사용안함" 33 | elseif GetLocale() == "zhTW" then 34 | DEBUGGING = "除錯" 35 | TOGGLE_DEBUGGING = "啟用/停用除錯功能" 36 | elseif GetLocale() == "zhCN" then 37 | DEBUGGING = "\232\176\131\232\175\149" 38 | TOGGLE_DEBUGGING = "\229\144\175\231\148\168/\231\166\129\231\148\168 \232\176\131\232\175\149" 39 | elseif GetLocale() == "ruRU" then 40 | DEBUGGING = "Отладка" 41 | TOGGLE_DEBUGGING = "Вкл./Выкл. отладку для этого аддона." 42 | else -- enUS 43 | DEBUGGING = "Debugging" 44 | TOGGLE_DEBUGGING = "Enable/disable debugging" 45 | end 46 | 47 | local table_setn 48 | do 49 | local version = GetBuildInfo() 50 | if string.find(version, "^2%.") then 51 | -- 2.0.0 52 | table_setn = function() end 53 | else 54 | table_setn = table.setn 55 | end 56 | end 57 | 58 | local math_mod = math.mod or math.fmod 59 | 60 | local AceOO = AceLibrary:GetInstance("AceOO-2.0") 61 | local AceDebug = AceOO.Mixin {"Debug", "CustomDebug", "IsDebugging", "SetDebugging", "SetDebugLevel", "LevelDebug", "CustomLevelDebug", "GetDebugLevel"} 62 | 63 | local function print(text, r, g, b, frame, delay) 64 | (frame or DEFAULT_CHAT_FRAME):AddMessage(text, r, g, b, 1, delay or 5) 65 | end 66 | 67 | local tmp 68 | 69 | function AceDebug:CustomDebug(r, g, b, frame, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 70 | if not self.debugging then return end 71 | 72 | local output = string.format("|cff7fff7f(DEBUG) %s:[%s%3d]|r", tostring(self), date("%H:%M:%S"), math_mod(GetTime(), 1) * 1000) 73 | 74 | if string.find(tostring(a1), "%%") then 75 | output = output .. " " .. string.format(tostring(a1), tostring(a2), tostring(a3), tostring(a4), tostring(a5), tostring(a6), tostring(a7), tostring(a8), tostring(a9), tostring(a10), tostring(a11), tostring(a12), tostring(a13), tostring(a14), tostring(a15), tostring(a16), tostring(a17), tostring(a18), tostring(a19), tostring(a20)) 76 | else 77 | if not tmp then 78 | tmp = {} 79 | end 80 | 81 | -- This block dynamically rebuilds the tmp array stopping on the first nil. 82 | table.insert(tmp, output) 83 | 84 | table.insert(tmp, tostring(a1)) 85 | table.insert(tmp, a2) 86 | table.insert(tmp, a3) 87 | table.insert(tmp, a4) 88 | table.insert(tmp, a5) 89 | table.insert(tmp, a6) 90 | table.insert(tmp, a7) 91 | table.insert(tmp, a8) 92 | table.insert(tmp, a9) 93 | table.insert(tmp, a10) 94 | table.insert(tmp, a11) 95 | table.insert(tmp, a12) 96 | table.insert(tmp, a13) 97 | table.insert(tmp, a14) 98 | table.insert(tmp, a15) 99 | table.insert(tmp, a16) 100 | table.insert(tmp, a17) 101 | table.insert(tmp, a18) 102 | table.insert(tmp, a19) 103 | table.insert(tmp, a20) 104 | while tmp[table.getn(tmp)] == nil do 105 | table.remove(tmp) 106 | end 107 | for k = 1, table.getn(tmp) do 108 | tmp[k] = tostring(tmp[k]) 109 | end 110 | 111 | output = table.concat(tmp, " ") 112 | 113 | for k,v in pairs(tmp) do 114 | tmp[k] = nil 115 | end 116 | table_setn(tmp, 0) 117 | end 118 | 119 | print(output, r, g, b, frame or self.debugFrame, delay) 120 | end 121 | 122 | function AceDebug:Debug(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 123 | AceDebug.CustomDebug(self, nil, nil, nil, nil, nil, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 124 | end 125 | 126 | function AceDebug:IsDebugging() 127 | return self.debugging 128 | end 129 | 130 | function AceDebug:SetDebugging(debugging) 131 | self.debugging = debugging 132 | end 133 | 134 | -- Takes a number 1-3 135 | -- Level 1: Critical messages that every user should receive 136 | -- Level 2: Should be used for local debugging (function calls, etc) 137 | -- Level 3: Very verbose debugging, will dump everything and anything 138 | -- If set to nil, you will receive no debug information 139 | function AceDebug:SetDebugLevel(level) 140 | AceDebug:argCheck(level, 1, "number", "nil") 141 | if not level then 142 | self.debuglevel = nil 143 | return 144 | end 145 | if level < 1 or level > 3 then 146 | AceDebug:error("Bad argument #1 to `SetDebugLevel`, must be a number 1-3") 147 | end 148 | self.debuglevel = level 149 | end 150 | 151 | function AceDebug:GetDebugLevel() 152 | return self.debuglevel 153 | end 154 | 155 | function AceDebug:CustomLevelDebug(level, r, g, b, frame, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 156 | if not self.debugging or not self.debuglevel then return end 157 | AceDebug:argCheck(level, 1, "number") 158 | if level < 1 or level > 3 then 159 | AceDebug:error("Bad argument #1 to `LevelDebug`, must be a number 1-3") 160 | end 161 | if level > self.debuglevel then return end 162 | 163 | local output = string.format("|cff7fff7f(DEBUG) %s:[%s.%3d]|r", tostring(self), date("%H:%M:%S"), math_mod(GetTime(), 1) * 1000) 164 | 165 | if string.find(tostring(a1), "%%") then 166 | output = output .. " " .. string.format(tostring(a1), tostring(a2), tostring(a3), tostring(a4), tostring(a5), tostring(a6), tostring(a7), tostring(a8), tostring(a9), tostring(a10), tostring(a11), tostring(a12), tostring(a13), tostring(a14), tostring(a15), tostring(a16), tostring(a17), tostring(a18), tostring(a19), tostring(a20)) 167 | else 168 | if not tmp then 169 | tmp = {} 170 | end 171 | 172 | -- This block dynamically rebuilds the tmp array stopping on the first nil. 173 | table.insert(tmp, output) 174 | 175 | table.insert(tmp, tostring(a1)) 176 | table.insert(tmp, a2) 177 | table.insert(tmp, a3) 178 | table.insert(tmp, a4) 179 | table.insert(tmp, a5) 180 | table.insert(tmp, a6) 181 | table.insert(tmp, a7) 182 | table.insert(tmp, a8) 183 | table.insert(tmp, a9) 184 | table.insert(tmp, a10) 185 | table.insert(tmp, a11) 186 | table.insert(tmp, a12) 187 | table.insert(tmp, a13) 188 | table.insert(tmp, a14) 189 | table.insert(tmp, a15) 190 | table.insert(tmp, a16) 191 | table.insert(tmp, a17) 192 | table.insert(tmp, a18) 193 | table.insert(tmp, a19) 194 | table.insert(tmp, a20) 195 | while tmp[table.getn(tmp)] == nil do 196 | table.remove(tmp) 197 | end 198 | for k = 1, table.getn(tmp) do 199 | tmp[k] = tostring(tmp[k]) 200 | end 201 | 202 | output = table.concat(tmp, " ") 203 | 204 | for k,v in pairs(tmp) do 205 | tmp[k] = nil 206 | end 207 | table_setn(tmp, 0) 208 | end 209 | 210 | print(output, r, g, b, frame or self.debugFrame, delay) 211 | end 212 | 213 | function AceDebug:LevelDebug(level, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 214 | if not self.debugging or not self.debuglevel then return end 215 | AceDebug:argCheck(level, 1, "number") 216 | if level < 1 or level > 3 then 217 | AceDebug:error("Bad argument #1 to `LevelDebug`, must be a number 1-3") 218 | end 219 | if level > self.debuglevel then return end 220 | 221 | AceDebug.CustomLevelDebug(self, level, nil, nil, nil, nil, nil, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) 222 | end 223 | 224 | 225 | local options 226 | function AceDebug:GetAceOptionsDataTable(target) 227 | if not options then 228 | options = { 229 | debug = { 230 | name = DEBUGGING, 231 | desc = TOGGLE_DEBUGGING, 232 | type = "toggle", 233 | get = "IsDebugging", 234 | set = "SetDebugging", 235 | order = -2, 236 | } 237 | } 238 | end 239 | return options 240 | end 241 | AceLibrary:Register(AceDebug, MAJOR_VERSION, MINOR_VERSION, AceDebug.activate) 242 | AceDebug = AceLibrary(MAJOR_VERSION) -------------------------------------------------------------------------------- /libs/AceHook-2.1/AceHook-2.1.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Name: AceHook-2.1 3 | Revision: $Rev: 17638 $ 4 | Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) 5 | Inspired By: Ace 1.x by Turan (turan@gryphon.com) 6 | Website: http://www.wowace.com/ 7 | Documentation: http://www.wowace.com/index.php/AceHook-2.1 8 | SVN: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.1 9 | Description: Mixin to allow for safe hooking of functions, methods, and scripts. 10 | Dependencies: AceLibrary, AceOO-2.0 11 | ]] 12 | 13 | local MAJOR_VERSION = "AceHook-2.1" 14 | local MINOR_VERSION = "$Revision: 17638 $" 15 | 16 | -- This ensures the code is only executed if the libary doesn't already exist, or is a newer version 17 | if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end 18 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end 19 | 20 | if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check 21 | if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end 22 | 23 | --[[--------------------------------------------------------------------------------- 24 | Create the library object 25 | ----------------------------------------------------------------------------------]] 26 | 27 | local AceOO = AceLibrary:GetInstance("AceOO-2.0") 28 | local AceHook = AceOO.Mixin { 29 | "Hook", 30 | "HookScript", 31 | "SecureHook", 32 | "Unhook", 33 | "UnhookAll", 34 | "HookReport", 35 | "IsHooked", 36 | } 37 | 38 | --[[--------------------------------------------------------------------------------- 39 | Library Definitions 40 | ----------------------------------------------------------------------------------]] 41 | 42 | local protFuncs = { 43 | CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true, 44 | TurnOrActionStart = true, TurnOrActionStop = true, 45 | PitchUpStart = true, PitchUpStop = true, 46 | PitchDownStart = true, PitchDownStop = true, 47 | MoveBackwardStart = true, MoveBackwardStop = true, 48 | MoveForwardStart = true, MoveForwardStop = true, 49 | Jump = true, StrafeLeftStart = true, 50 | StrafeLeftStop = true, StrafeRightStart = true, 51 | StrafeRightStop = true, ToggleMouseMove = true, 52 | ToggleRun = true, TurnLeftStart = true, 53 | TurnLeftStop = true, TurnRightStart = true, 54 | TurnRightStop = true, 55 | } 56 | 57 | local function issecurevariable(x) 58 | if protFuncs[x] then 59 | return 1 60 | else 61 | return nil 62 | end 63 | end 64 | 65 | local _G = getfenv(0) 66 | 67 | local function hooksecurefunc(arg1, arg2, arg3) 68 | if type(arg1) == "string" then 69 | arg1, arg2, arg3 = _G, arg1, arg2 70 | end 71 | local orig = arg1[arg2] 72 | arg1[arg2] = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 73 | local x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20 = orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 74 | 75 | arg3(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 76 | 77 | return x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20 78 | end 79 | end 80 | 81 | local protectedScripts = { 82 | OnClick = true, 83 | } 84 | 85 | 86 | local handlers, scripts, actives, registry 87 | 88 | --[[--------------------------------------------------------------------------------- 89 | Private definitions (Not exposed) 90 | ----------------------------------------------------------------------------------]] 91 | 92 | local new, del 93 | do 94 | local list = setmetatable({}, {__mode = "k"}) 95 | function new() 96 | local t = next(list) 97 | if not t then 98 | return {} 99 | end 100 | list[t] = nil 101 | return t 102 | end 103 | 104 | function del(t) 105 | setmetatable(t, nil) 106 | for k in pairs(t) do 107 | t[k] = nil 108 | end 109 | list[t] = true 110 | end 111 | end 112 | 113 | local function createFunctionHook(self, func, handler, orig, secure) 114 | if not secure then 115 | if type(handler) == "string" then 116 | -- The handler is a method, need to self it 117 | local uid 118 | uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 119 | if actives[uid] then 120 | return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 121 | else 122 | return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 123 | end 124 | end 125 | return uid 126 | else 127 | -- The handler is a function, just call it 128 | local uid 129 | uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 130 | if actives[uid] then 131 | return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 132 | else 133 | return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 134 | end 135 | end 136 | return uid 137 | end 138 | else 139 | -- secure hooks don't call the original method 140 | if type(handler) == "string" then 141 | -- The handler is a method, need to self it 142 | local uid 143 | uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 144 | if actives[uid] then 145 | return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 146 | end 147 | end 148 | return uid 149 | else 150 | -- The handler is a function, just call it 151 | local uid 152 | uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 153 | if actives[uid] then 154 | return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 155 | end 156 | end 157 | return uid 158 | end 159 | end 160 | end 161 | 162 | local function createMethodHook(self, object, method, handler, orig, secure, script) 163 | if script then 164 | if type(handler) == "string" then 165 | local uid 166 | uid = function() 167 | if actives[uid] then 168 | return self[handler](self, object) 169 | else 170 | return orig() 171 | end 172 | end 173 | return uid 174 | else 175 | -- The handler is a function, just call it 176 | local uid 177 | uid = function() 178 | if actives[uid] then 179 | return handler(object) 180 | else 181 | return orig() 182 | end 183 | end 184 | return uid 185 | end 186 | elseif not secure then 187 | if type(handler) == "string" then 188 | local uid 189 | uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 190 | if actives[uid] then 191 | return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 192 | else 193 | return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 194 | end 195 | end 196 | return uid 197 | else 198 | -- The handler is a function, just call it 199 | local uid 200 | uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 201 | if actives[uid] then 202 | return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 203 | else 204 | return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 205 | end 206 | end 207 | return uid 208 | end 209 | else 210 | -- secure hooks don't call the original method 211 | if type(handler) == "string" then 212 | local uid 213 | uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 214 | if actives[uid] then 215 | return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 216 | end 217 | end 218 | return uid 219 | else 220 | -- The handler is a function, just call it 221 | local uid 222 | uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 223 | if actives[uid] then 224 | return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 225 | end 226 | end 227 | return uid 228 | end 229 | end 230 | end 231 | 232 | local function hookFunction(self, func, handler, secure) 233 | local orig = _G[func] 234 | 235 | if not orig or type(orig) ~= "function" then 236 | AceHook:error("Attempt to hook a non-existant function %q", func) 237 | end 238 | 239 | if not handler then 240 | handler = func 241 | end 242 | 243 | if registry[self][func] then 244 | local uid = registry[self][func] 245 | 246 | if actives[uid] then 247 | -- We have an active hook from this source. Don't multi-hook 248 | AceHook:error("%q already has an active hook from this source.", func) 249 | end 250 | 251 | if handlers[uid] == handler then 252 | -- The hook is inactive, so reactivate it 253 | actives[uid] = true 254 | return 255 | else 256 | AceHook:error("There is a stale hook for %q can't hook or reactivate.", func) 257 | end 258 | end 259 | 260 | if type(handler) == "string" then 261 | if type(self[handler]) ~= "function" then 262 | AceHook:error("Could not find the the handler %q when hooking function %q", handler, func) 263 | end 264 | elseif type(handler) ~= "function" then 265 | AceHook:error("Could not find the handler you supplied when hooking %q", func) 266 | end 267 | 268 | local uid = createFunctionHook(self, func, handler, orig, secure) 269 | registry[self][func] = uid 270 | actives[uid] = true 271 | handlers[uid] = handler 272 | 273 | if not secure then 274 | _G[func] = uid 275 | self.hooks[func] = orig 276 | else 277 | hooksecurefunc(func, uid) 278 | end 279 | end 280 | 281 | local function unhookFunction(self, func) 282 | if not registry[self][func] then 283 | AceHook:error("Tried to unhook %q which is not currently hooked.", func) 284 | end 285 | 286 | local uid = registry[self][func] 287 | 288 | if actives[uid] then 289 | -- See if we own the global function 290 | if self.hooks[func] and _G[func] == uid then 291 | _G[func] = self.hooks[func] 292 | self.hooks[func] = nil 293 | registry[self][func] = nil 294 | handlers[uid] = nil 295 | scripts[uid] = nil 296 | actives[uid] = nil 297 | -- Magically all-done 298 | else 299 | actives[uid] = nil 300 | end 301 | end 302 | end 303 | 304 | local function hookMethod(self, obj, method, handler, script, secure) 305 | if not handler then 306 | handler = method 307 | end 308 | 309 | if not obj or type(obj) ~= "table" then 310 | AceHook:error("The object you supplied could not be found, or isn't a table.") 311 | end 312 | 313 | local uid = registry[self][obj] and registry[self][obj][method] 314 | if uid then 315 | if actives[uid] then 316 | -- We have an active hook from this source. Don't multi-hook 317 | AceHook:error("%q already has an active hook from this source.", method) 318 | end 319 | 320 | if handlers[uid] == handler then 321 | -- The hook is inactive, reactivate it. 322 | actives[uid] = true 323 | return 324 | else 325 | AceHook:error("There is a stale hook for %q can't hook or reactivate.", method) 326 | end 327 | end 328 | 329 | if type(handler) == "string" then 330 | if type(self[handler]) ~= "function" then 331 | AceHook:error("Could not find the handler %q you supplied when hooking method %q", handler, method) 332 | end 333 | elseif type(handler) ~= "function" then 334 | AceHook:error("Could not find the handler you supplied when hooking method %q", method) 335 | end 336 | 337 | local orig 338 | if script then 339 | if not obj.GetScript then 340 | AceHook:error("The object you supplied does not have a GetScript method.") 341 | end 342 | if not obj:HasScript(method) then 343 | AceHook:error("The object you supplied doesn't allow the %q method.", method) 344 | end 345 | 346 | orig = obj:GetScript(method) 347 | if type(orig) ~= "function" then 348 | -- Sometimes there is not a original function for a script. 349 | orig = function() end 350 | end 351 | else 352 | orig = obj[method] 353 | end 354 | if not orig then 355 | AceHook:error("Could not find the method or script %q you are trying to hook.", method) 356 | end 357 | 358 | if not registry[self][obj] then 359 | registry[self][obj] = new() 360 | end 361 | 362 | if not self.hooks[obj] then 363 | self.hooks[obj] = new() 364 | end 365 | 366 | local uid = createMethodHook(self, obj, method, handler, orig, secure, script) 367 | registry[self][obj][method] = uid 368 | actives[uid] = true 369 | handlers[uid] = handler 370 | scripts[uid] = script and true or nil 371 | 372 | if script then 373 | obj:SetScript(method, uid) 374 | self.hooks[obj][method] = orig 375 | elseif not secure then 376 | obj[method] = uid 377 | self.hooks[obj][method] = orig 378 | else 379 | hooksecurefunc(obj, method, uid) 380 | end 381 | end 382 | 383 | local function unhookMethod(self, obj, method) 384 | if not registry[self][obj] or not registry[self][obj][method] then 385 | AceHook:error("Attempt to unhook a method %q that is not currently hooked.", method) 386 | return 387 | end 388 | 389 | local uid = registry[self][obj][method] 390 | 391 | if actives[uid] then 392 | if scripts[uid] then -- If this is a script 393 | if obj:GetScript(method) == uid then 394 | -- We own the script. Revert to normal. 395 | obj:SetScript(method, self.hooks[obj][method]) 396 | self.hooks[obj][method] = nil 397 | registry[self][obj][method] = nil 398 | handlers[uid] = nil 399 | scripts[uid] = nil 400 | actives[uid] = nil 401 | else 402 | actives[uid] = nil 403 | end 404 | else 405 | if self.hooks[obj] and self.hooks[obj][method] and obj[method] == uid then 406 | -- We own the method. Revert to normal. 407 | obj[method] = self.hooks[obj][method] 408 | self.hooks[obj][method] = nil 409 | registry[self][obj][method] = nil 410 | handlers[uid] = nil 411 | actives[uid] = nil 412 | else 413 | actives[uid] = nil 414 | end 415 | end 416 | end 417 | if self.hooks[obj] and not next(self.hooks[obj]) then 418 | self.hooks[obj] = del(self.hooks[obj]) 419 | end 420 | if not next(registry[self][obj]) then 421 | registry[self][obj] = del(registry[self][obj]) 422 | end 423 | end 424 | 425 | -- ("function" [, handler] [, hookSecure]) or (object, "method" [, handler] [, hookSecure]) 426 | function AceHook:Hook(object, method, handler, hookSecure) 427 | if type(object) == "string" then 428 | method, handler, hookSecure = object, method, handler 429 | if handler == true then 430 | handler, hookSecure = nil, true 431 | end 432 | if not hookSecure and issecurevariable(method) then 433 | AceHook:error("Attempt to hook secure function %q. Use `SecureHook' or add `true' to the argument list to override.", method) 434 | end 435 | AceHook:argCheck(handler, 3, "function", "string", "nil") 436 | AceHook:argCheck(hookSecure, 4, "boolean", "nil") 437 | hookFunction(self, method, handler, false) 438 | else 439 | if handler == true then 440 | handler, hookSecure = nil, true 441 | end 442 | if not hookSecure and issecurevariable(object, method) then 443 | AceHook:error("Attempt to hook secure method %q. Use `SecureHook' or add `true' to the argument list to override.", method) 444 | end 445 | AceHook:argCheck(object, 2, "table") 446 | AceHook:argCheck(method, 3, "string") 447 | AceHook:argCheck(handler, 4, "function", "string", "nil") 448 | AceHook:argCheck(hookSecure, 5, "boolean", "nil") 449 | hookMethod(self, object, method, handler, false, false) 450 | end 451 | end 452 | 453 | -- ("function", handler) or (object, "method", handler) 454 | function AceHook:SecureHook(object, method, handler) 455 | if type(object) == "string" then 456 | method, handler = object, method 457 | AceHook:argCheck(handler, 3, "function", "string", "nil") 458 | hookFunction(self, method, handler, true) 459 | else 460 | AceHook:argCheck(object, 2, "table") 461 | AceHook:argCheck(method, 3, "string") 462 | AceHook:argCheck(handler, 4, "function", "string", "nil") 463 | hookMethod(self, object, method, handler, false, true) 464 | end 465 | end 466 | 467 | function AceHook:HookScript(frame, script, handler) 468 | AceHook:argCheck(frame, 2, "table") 469 | if not frame[0] or type(frame.IsFrameType) ~= "function" then 470 | AceHook:error("Bad argument #2 to `HookScript'. Expected frame.") 471 | end 472 | AceHook:argCheck(script, 3, "string") 473 | AceHook:argCheck(handler, 4, "function", "string", "nil") 474 | hookMethod(self, frame, script, handler, true, false) 475 | end 476 | 477 | -- ("function") or (object, "method") 478 | function AceHook:IsHooked(obj, method) 479 | if type(obj) == "string" then 480 | if registry[self][obj] and actives[registry[self][obj]] then 481 | return true, handlers[registry[self][obj]] 482 | end 483 | else 484 | AceHook:argCheck(obj, 2, "string", "table") 485 | AceHook:argCheck(method, 3, "string") 486 | if registry[self][obj] and registry[self][obj][method] and actives[registry[self][obj][method]] then 487 | return true, handlers[registry[self][obj][method]] 488 | end 489 | end 490 | 491 | return false, nil 492 | end 493 | 494 | -- ("function") or (object, "method") 495 | function AceHook:Unhook(obj, method) 496 | if type(obj) == "string" then 497 | unhookFunction(self, obj) 498 | else 499 | AceHook:argCheck(obj, 2, "string", "table") 500 | AceHook:argCheck(method, 3, "string") 501 | unhookMethod(self, obj, method) 502 | end 503 | end 504 | 505 | function AceHook:UnhookAll() 506 | for key, value in pairs(registry[self]) do 507 | if type(key) == "table" then 508 | for method in pairs(value) do 509 | self:Unhook(key, method) 510 | end 511 | else 512 | self:Unhook(key) 513 | end 514 | end 515 | end 516 | 517 | function AceHook:HookReport() 518 | DEFAULT_CHAT_FRAME:AddMessage("This is a list of all active hooks for this object:") 519 | if not next(registry[self]) then 520 | DEFAULT_CHAT_FRAME:AddMessage("No hooks") 521 | end 522 | 523 | for key, value in pairs(registry[self]) do 524 | if type(value) == "table" then 525 | for method, uid in pairs(value) do 526 | DEFAULT_CHAT_FRAME:AddMessage(string.format("object: %s method: %q |cff%s|r%s", tostring(key), method, actives[uid] and "00ff00Active" or "ffff00Inactive", not self.hooks[key][method] and " |cff7f7fff-Secure-|r" or "")) 527 | end 528 | else 529 | DEFAULT_CHAT_FRAME:AddMessage(string.format("function: %q |cff%s|r%s", tostring(key), actives[value] and "00ff00Active" or "ffff00Inactive", not self.hooks[key] and " |cff7f7fff-Secure-|r" or "")) 530 | end 531 | end 532 | end 533 | 534 | function AceHook:OnInstanceInit(object) 535 | if not object.hooks then 536 | object.hooks = new() 537 | end 538 | if not registry[object] then 539 | registry[object] = new() 540 | end 541 | end 542 | 543 | AceHook.OnManualEmbed = AceHook.OnInstanceInit 544 | 545 | function AceHook:OnEmbedDisable(target) 546 | self.UnhookAll(target) 547 | end 548 | 549 | local function activate(self, oldLib, oldDeactivate) 550 | AceHook = self 551 | 552 | self.handlers = oldLib and oldLib.handlers or {} 553 | self.registry = oldLib and oldLib.registry or {} 554 | self.scripts = oldLib and oldLib.scripts or {} 555 | self.actives = oldLib and oldLib.actives or {} 556 | 557 | handlers = self.handlers 558 | registry = self.registry 559 | scripts = self.scripts 560 | actives = self.actives 561 | 562 | AceHook.super.activate(self, oldLib, oldDeactivate) 563 | 564 | if oldDeactivate then 565 | oldDeactivate(oldLib) 566 | end 567 | end 568 | 569 | AceLibrary:Register(AceHook, MAJOR_VERSION, MINOR_VERSION, activate) 570 | -------------------------------------------------------------------------------- /libs/AceLocale-2.2/AceLocale-2.2.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Name: AceLocale-2.2 3 | Revision: $Rev: 17638 $ 4 | Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) 5 | Inspired By: Ace 1.x by Turan (turan@gryphon.com) 6 | Website: http://www.wowace.com/ 7 | Documentation: http://www.wowace.com/index.php/AceLocale-2.2 8 | SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.2 9 | Description: Localization library for addons to use to handle proper 10 | localization and internationalization. 11 | Dependencies: AceLibrary 12 | ]] 13 | 14 | local MAJOR_VERSION = "AceLocale-2.2" 15 | local MINOR_VERSION = "$Revision: 17638 $" 16 | 17 | if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end 18 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end 19 | 20 | if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check 21 | local AceLocale = {} 22 | 23 | local DEFAULT_LOCALE = "enUS" 24 | local _G = getfenv(0) 25 | 26 | local BASE_TRANSLATIONS, DEBUGGING, TRANSLATIONS, BASE_LOCALE, TRANSLATION_TABLES, REVERSE_TRANSLATIONS, STRICTNESS, DYNAMIC_LOCALES, CURRENT_LOCALE, NAME 27 | 28 | local rawget = rawget 29 | local rawset = rawset 30 | local type = type 31 | 32 | local newRegistries = {} 33 | local scheduleClear 34 | 35 | local lastSelf 36 | local __index = function(self, key) 37 | lastSelf = self 38 | local value = (rawget(self, TRANSLATIONS) or AceLocale.prototype)[key] 39 | rawset(self, key, value) 40 | return value 41 | end 42 | 43 | local __newindex = function(self, k, v) 44 | if type(v) ~= "function" and type(k) ~= "table" then 45 | AceLocale.error(self, "Cannot change the values of an AceLocale instance.") 46 | end 47 | rawset(self, k, v) 48 | end 49 | 50 | local __tostring = function(self) 51 | if type(rawget(self, 'GetLibraryVersion')) == "function" then 52 | return self:GetLibraryVersion() 53 | else 54 | return "AceLocale(" .. self[NAME] .. ")" 55 | end 56 | end 57 | 58 | local function clearCache(self) 59 | if not rawget(self, BASE_TRANSLATIONS) then 60 | return 61 | end 62 | 63 | local cache = self[BASE_TRANSLATIONS] 64 | rawset(self, REVERSE_TRANSLATIONS, nil) 65 | 66 | for k in pairs(self) do 67 | if rawget(cache, k) ~= nil then 68 | self[k] = nil 69 | end 70 | end 71 | rawset(self, 'tmp', true) 72 | self.tmp = nil 73 | end 74 | 75 | local function refixInstance(instance) 76 | if getmetatable(instance) then 77 | setmetatable(instance, nil) 78 | end 79 | local translations = instance[TRANSLATIONS] 80 | if translations then 81 | if getmetatable(translations) then 82 | setmetatable(translations, nil) 83 | end 84 | local baseTranslations = instance[BASE_TRANSLATIONS] 85 | if getmetatable(baseTranslations) then 86 | setmetatable(baseTranslations, nil) 87 | end 88 | if translations == baseTranslations or instance[STRICTNESS] then 89 | setmetatable(instance, { 90 | __index = __index, 91 | __newindex = __newindex, 92 | __tostring = __tostring 93 | }) 94 | 95 | setmetatable(translations, { 96 | __index = AceLocale.prototype 97 | }) 98 | else 99 | setmetatable(instance, { 100 | __index = __index, 101 | __newindex = __newindex, 102 | __tostring = __tostring 103 | }) 104 | 105 | setmetatable(translations, { 106 | __index = baseTranslations, 107 | }) 108 | 109 | setmetatable(baseTranslations, { 110 | __index = AceLocale.prototype, 111 | }) 112 | end 113 | else 114 | setmetatable(instance, { 115 | __index = __index, 116 | __newindex = __newindex, 117 | __tostring = __tostring, 118 | }) 119 | end 120 | clearCache(instance) 121 | newRegistries[instance] = true 122 | scheduleClear() 123 | return instance 124 | end 125 | 126 | function AceLocale:new(name) 127 | self:argCheck(name, 2, "string") 128 | 129 | if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then 130 | return self.registry[name] 131 | end 132 | 133 | AceLocale.registry[name] = refixInstance({ 134 | [STRICTNESS] = false, 135 | [NAME] = name, 136 | }) 137 | newRegistries[AceLocale.registry[name]] = true 138 | return AceLocale.registry[name] 139 | end 140 | 141 | AceLocale.prototype = { class = AceLocale } 142 | 143 | function AceLocale.prototype:EnableDebugging() 144 | if rawget(self, BASE_TRANSLATIONS) then 145 | AceLocale.error(self, "Cannot enable debugging after a translation has been registered.") 146 | end 147 | rawset(self, DEBUGGING, true) 148 | end 149 | 150 | function AceLocale.prototype:EnableDynamicLocales(override) 151 | AceLocale.argCheck(self, override, 2, "boolean", "nil") 152 | if not override and rawget(self, BASE_TRANSLATIONS) then 153 | AceLocale.error(self, "Cannot enable dynamic locales after a translation has been registered.") 154 | end 155 | if not rawget(self, DYNAMIC_LOCALES) then 156 | rawset(self, DYNAMIC_LOCALES, true) 157 | if rawget(self, BASE_LOCALE) then 158 | if not rawget(self, TRANSLATION_TABLES) then 159 | rawset(self, TRANSLATION_TABLES, {}) 160 | end 161 | self[TRANSLATION_TABLES][self[BASE_LOCALE]] = self[BASE_TRANSLATIONS] 162 | self[TRANSLATION_TABLES][self[CURRENT_LOCALE]] = self[TRANSLATIONS] 163 | end 164 | end 165 | end 166 | 167 | function AceLocale.prototype:RegisterTranslations(locale, func) 168 | AceLocale.argCheck(self, locale, 2, "string") 169 | AceLocale.argCheck(self, func, 3, "function") 170 | 171 | if locale == rawget(self, BASE_LOCALE) then 172 | AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale) 173 | end 174 | 175 | if rawget(self, BASE_TRANSLATIONS) and GetLocale() ~= locale then 176 | if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then 177 | if not rawget(self, TRANSLATION_TABLES) then 178 | rawset(self, TRANSLATION_TABLES, {}) 179 | end 180 | if self[TRANSLATION_TABLES][locale] then 181 | AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale) 182 | end 183 | local t = func() 184 | func = nil 185 | if type(t) ~= "table" then 186 | AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t)) 187 | end 188 | self[TRANSLATION_TABLES][locale] = t 189 | t = nil 190 | end 191 | func = nil 192 | return 193 | end 194 | local t = func() 195 | func = nil 196 | if type(t) ~= "table" then 197 | AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t)) 198 | end 199 | 200 | rawset(self, TRANSLATIONS, t) 201 | if not rawget(self, BASE_TRANSLATIONS) then 202 | rawset(self, BASE_TRANSLATIONS, t) 203 | rawset(self, BASE_LOCALE, locale) 204 | for key,value in pairs(t) do 205 | if value == true then 206 | t[key] = key 207 | end 208 | end 209 | else 210 | for key, value in pairs(self[TRANSLATIONS]) do 211 | if not rawget(self[BASE_TRANSLATIONS], key) then 212 | AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale) 213 | end 214 | if value == true then 215 | AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, BASE_LOCALE), locale) 216 | end 217 | end 218 | end 219 | rawset(self, CURRENT_LOCALE, locale) 220 | refixInstance(self) 221 | if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then 222 | if not rawget(self, TRANSLATION_TABLES) then 223 | rawset(self, TRANSLATION_TABLES, {}) 224 | end 225 | self[TRANSLATION_TABLES][locale] = t 226 | end 227 | t = nil 228 | end 229 | 230 | function AceLocale.prototype:SetLocale(locale) 231 | AceLocale.argCheck(self, locale, 2, "string", "boolean") 232 | if not rawget(self, DYNAMIC_LOCALES) then 233 | AceLocale.error(self, "Cannot call `SetLocale' without first calling `EnableDynamicLocales'.") 234 | end 235 | if not rawget(self, TRANSLATION_TABLES) then 236 | AceLocale.error(self, "Cannot call `SetLocale' without first calling `RegisterTranslations'.") 237 | end 238 | if locale == true then 239 | locale = GetLocale() 240 | if not self[TRANSLATION_TABLES][locale] then 241 | locale = self[BASE_LOCALE] 242 | end 243 | end 244 | 245 | if self[CURRENT_LOCALE] == locale then 246 | return 247 | end 248 | 249 | if not self[TRANSLATION_TABLES][locale] then 250 | AceLocale.error(self, "Locale %q not registered.", locale) 251 | end 252 | 253 | self[TRANSLATIONS] = self[TRANSLATION_TABLES][locale] 254 | self[CURRENT_LOCALE] = locale 255 | refixInstance(self) 256 | end 257 | 258 | function AceLocale.prototype:GetLocale() 259 | if not rawget(self, TRANSLATION_TABLES) then 260 | AceLocale.error(self, "Cannot call `GetLocale' without first calling `RegisterTranslations'.") 261 | end 262 | return self[CURRENT_LOCALE] 263 | end 264 | 265 | local function iter(t, position) 266 | return (next(t, position)) 267 | end 268 | 269 | function AceLocale.prototype:IterateAvailableLocales() 270 | if not rawget(self, DYNAMIC_LOCALES) then 271 | AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `EnableDynamicLocales'.") 272 | end 273 | if not rawget(self, TRANSLATION_TABLES) then 274 | AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `RegisterTranslations'.") 275 | end 276 | return iter, self[TRANSLATION_TABLES], nil 277 | end 278 | 279 | function AceLocale.prototype:HasLocale(locale) 280 | if not rawget(self, DYNAMIC_LOCALES) then 281 | AceLocale.error(self, "Cannot call `HasLocale' without first calling `EnableDynamicLocales'.") 282 | end 283 | AceLocale.argCheck(self, locale, 2, "string") 284 | return rawget(self, TRANSLATION_TABLES) and self[TRANSLATION_TABLES][locale] ~= nil 285 | end 286 | 287 | function AceLocale.prototype:SetStrictness(strict) 288 | AceLocale.argCheck(self, strict, 2, "boolean") 289 | local mt = getmetatable(self) 290 | if not mt then 291 | AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.") 292 | end 293 | if not rawget(self, TRANSLATIONS) then 294 | AceLocale.error(self, "No translations registered.") 295 | end 296 | rawset(self, STRICTNESS, strict) 297 | refixInstance(self) 298 | end 299 | 300 | local function initReverse(self) 301 | rawset(self, REVERSE_TRANSLATIONS, {}) 302 | local alpha = self[TRANSLATIONS] 303 | local bravo = self[REVERSE_TRANSLATIONS] 304 | for base, localized in pairs(alpha) do 305 | bravo[localized] = base 306 | end 307 | end 308 | 309 | function AceLocale.prototype:GetTranslation(text) 310 | AceLocale.argCheck(self, text, 1, "string", "number") 311 | if not rawget(self, TRANSLATIONS) then 312 | AceLocale.error(self, "No translations registered") 313 | end 314 | return self[text] 315 | end 316 | 317 | function AceLocale.prototype:GetStrictTranslation(text) 318 | AceLocale.argCheck(self, text, 1, "string", "number") 319 | local x = rawget(self, TRANSLATIONS) 320 | if not x then 321 | AceLocale.error(self, "No translations registered") 322 | end 323 | local value = rawget(x, text) 324 | if value == nil then 325 | AceLocale.error(self, "Translation %q does not exist for locale %s", text, self[CURRENT_LOCALE]) 326 | end 327 | return value 328 | end 329 | 330 | function AceLocale.prototype:GetReverseTranslation(text) 331 | local x = rawget(self, REVERSE_TRANSLATIONS) 332 | if not x then 333 | if not rawget(self, TRANSLATIONS) then 334 | AceLocale.error(self, "No translations registered") 335 | end 336 | initReverse(self) 337 | x = self[REVERSE_TRANSLATIONS] 338 | end 339 | local translation = x[text] 340 | if not translation then 341 | AceLocale.error(self, "Reverse translation for %q does not exist", text) 342 | end 343 | return translation 344 | end 345 | 346 | function AceLocale.prototype:GetIterator() 347 | local x = rawget(self, TRANSLATIONS) 348 | if not x then 349 | AceLocale.error(self, "No translations registered") 350 | end 351 | return next, x, nil 352 | end 353 | 354 | function AceLocale.prototype:GetReverseIterator() 355 | local x = rawget(self, REVERSE_TRANSLATIONS) 356 | if not x then 357 | if not rawget(self, TRANSLATIONS) then 358 | AceLocale.error(self, "No translations registered") 359 | end 360 | initReverse(self) 361 | x = self[REVERSE_TRANSLATIONS] 362 | end 363 | return next, x, nil 364 | end 365 | 366 | function AceLocale.prototype:HasTranslation(text) 367 | AceLocale.argCheck(self, text, 1, "string", "number") 368 | local x = rawget(self, TRANSLATIONS) 369 | if not x then 370 | AceLocale.error(self, "No translations registered") 371 | end 372 | return rawget(x, text) and true 373 | end 374 | 375 | function AceLocale.prototype:HasReverseTranslation(text) 376 | local x = rawget(self, REVERSE_TRANSLATIONS) 377 | if not x then 378 | if not rawget(self, TRANSLATIONS) then 379 | AceLocale.error(self, "No translations registered") 380 | end 381 | initReverse(self) 382 | x = self[REVERSE_TRANSLATIONS] 383 | end 384 | return x[text] and true 385 | end 386 | 387 | function AceLocale.prototype:Debug() 388 | if not rawget(self, DEBUGGING) then 389 | return 390 | end 391 | local words = {} 392 | local locales = {"enUS", "deDE", "frFR", "koKR", "zhCN", "zhTW", "esES"} 393 | local localizations = {} 394 | DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---") 395 | for _,locale in ipairs(locales) do 396 | if not self[TRANSLATION_TABLES][locale] then 397 | DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q not found", locale)) 398 | else 399 | localizations[locale] = self[TRANSLATION_TABLES][locale] 400 | end 401 | end 402 | local localeDebug = {} 403 | for locale, localization in pairs(localizations) do 404 | localeDebug[locale] = {} 405 | for word in pairs(localization) do 406 | if type(localization[word]) == "table" then 407 | if type(words[word]) ~= "table" then 408 | words[word] = {} 409 | end 410 | for bit in pairs(localization[word]) do 411 | if type(localization[word][bit]) == "string" then 412 | words[word][bit] = true 413 | end 414 | end 415 | elseif type(localization[word]) == "string" then 416 | words[word] = true 417 | end 418 | end 419 | end 420 | for word in pairs(words) do 421 | if type(words[word]) == "table" then 422 | for bit in pairs(words[word]) do 423 | for locale, localization in pairs(localizations) do 424 | if not rawget(localization, word) or not localization[word][bit] then 425 | localeDebug[locale][word .. "::" .. bit] = true 426 | end 427 | end 428 | end 429 | else 430 | for locale, localization in pairs(localizations) do 431 | if not rawget(localization, word) then 432 | localeDebug[locale][word] = true 433 | end 434 | end 435 | end 436 | end 437 | for locale, t in pairs(localeDebug) do 438 | if not next(t) then 439 | DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q complete", locale)) 440 | else 441 | DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q missing:", locale)) 442 | for word in pairs(t) do 443 | DEFAULT_CHAT_FRAME:AddMessage(string.format(" %q", word)) 444 | end 445 | end 446 | end 447 | DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---") 448 | end 449 | 450 | setmetatable(AceLocale.prototype, { 451 | __index = function(self, k) 452 | if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion" and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later. 453 | AceLocale.error(lastSelf or self, "Translation %q does not exist.", k) 454 | end 455 | return nil 456 | end 457 | }) 458 | 459 | local function activate(self, oldLib, oldDeactivate) 460 | AceLocale = self 461 | 462 | self.frame = oldLib and oldLib.frame or CreateFrame("Frame") 463 | self.registry = oldLib and oldLib.registry or {} 464 | self.BASE_TRANSLATIONS = oldLib and oldLib.BASE_TRANSLATIONS or {} 465 | self.DEBUGGING = oldLib and oldLib.DEBUGGING or {} 466 | self.TRANSLATIONS = oldLib and oldLib.TRANSLATIONS or {} 467 | self.BASE_LOCALE = oldLib and oldLib.BASE_LOCALE or {} 468 | self.TRANSLATION_TABLES = oldLib and oldLib.TRANSLATION_TABLES or {} 469 | self.REVERSE_TRANSLATIONS = oldLib and oldLib.REVERSE_TRANSLATIONS or {} 470 | self.STRICTNESS = oldLib and oldLib.STRICTNESS or {} 471 | self.NAME = oldLib and oldLib.NAME or {} 472 | self.DYNAMIC_LOCALES = oldLib and oldLib.DYNAMIC_LOCALES or {} 473 | self.CURRENT_LOCALE = oldLib and oldLib.CURRENT_LOCALE or {} 474 | 475 | BASE_TRANSLATIONS = self.BASE_TRANSLATIONS 476 | DEBUGGING = self.DEBUGGING 477 | TRANSLATIONS = self.TRANSLATIONS 478 | BASE_LOCALE = self.BASE_LOCALE 479 | TRANSLATION_TABLES = self.TRANSLATION_TABLES 480 | REVERSE_TRANSLATIONS = self.REVERSE_TRANSLATIONS 481 | STRICTNESS = self.STRICTNESS 482 | NAME = self.NAME 483 | DYNAMIC_LOCALES = self.DYNAMIC_LOCALES 484 | CURRENT_LOCALE = self.CURRENT_LOCALE 485 | 486 | 487 | local GetTime = GetTime 488 | local timeUntilClear = GetTime() + 5 489 | scheduleClear = function() 490 | if next(newRegistries) then 491 | self.frame:Show() 492 | timeUntilClear = GetTime() + 5 493 | end 494 | end 495 | 496 | if not self.registry then 497 | self.registry = {} 498 | else 499 | for name, instance in pairs(self.registry) do 500 | local name = name 501 | local mt = getmetatable(instance) 502 | setmetatable(instance, nil) 503 | instance[NAME] = name 504 | local strict 505 | if instance[STRICTNESS] ~= nil then 506 | strict = instance[STRICTNESS] 507 | elseif instance[TRANSLATIONS] ~= instance[BASE_TRANSLATIONS] then 508 | if getmetatable(instance[TRANSLATIONS]).__index == oldLib.prototype then 509 | strict = true 510 | end 511 | end 512 | instance[STRICTNESS] = strict and true or false 513 | refixInstance(instance) 514 | end 515 | end 516 | 517 | self.frame:SetScript("OnEvent", scheduleClear) 518 | self.frame:SetScript("OnUpdate", function() -- (this, elapsed) 519 | if timeUntilClear - GetTime() <= 0 then 520 | self.frame:Hide() 521 | for k in pairs(newRegistries) do 522 | clearCache(k) 523 | newRegistries[k] = nil 524 | k = nil 525 | end 526 | end 527 | end) 528 | self.frame:UnregisterAllEvents() 529 | self.frame:RegisterEvent("ADDON_LOADED") 530 | self.frame:RegisterEvent("PLAYER_ENTERING_WORLD") 531 | self.frame:Show() 532 | 533 | if oldDeactivate then 534 | oldDeactivate(oldLib) 535 | end 536 | end 537 | 538 | AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate) 539 | -------------------------------------------------------------------------------- /libs/Banzai-1.0/Banzai-1.0.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Name: Banzai-1.0 3 | Revision: $Rev: 14544 $ 4 | Author(s): Rabbit (rabbit.magtheridon@gmail.com), maia 5 | Documentation: http://www.wowace.com/index.php/Banzai-1.0_API_Documentation 6 | SVN: http://svn.wowace.com/root/trunk/BanzaiLib/Banzai-1.0 7 | Description: Aggro notification library. 8 | Dependencies: AceLibrary, AceEvent-2.0, RosterLib-2.0 9 | ]] 10 | 11 | ------------------------------------------------------------------------------- 12 | -- Locals 13 | ------------------------------------------------------------------------------- 14 | 15 | local MAJOR_VERSION = "Banzai-1.0" 16 | local MINOR_VERSION = "$Revision: 14544 $" 17 | 18 | if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end 19 | if not AceLibrary:HasInstance("RosterLib-2.0") then error(MAJOR_VERSION .. " requires RosterLib-2.0.") end 20 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end 21 | 22 | local lib = {} 23 | AceLibrary("AceEvent-2.0"):embed(lib) 24 | 25 | local RL = nil 26 | local roster = nil 27 | local playerName = nil 28 | 29 | ------------------------------------------------------------------------------- 30 | -- Compost Heap, courtesy of Tekkub/SEEA. 31 | ------------------------------------------------------------------------------- 32 | 33 | local table_setn 34 | do 35 | local version = GetBuildInfo() 36 | if string.find(version, "^2%.") then 37 | -- 2.0.0 38 | table_setn = function() end 39 | else 40 | table_setn = table.setn 41 | end 42 | end 43 | 44 | local heap = {} 45 | setmetatable(heap, {__mode = "kv"}) 46 | 47 | local function acquire() 48 | local t = next(heap) 49 | if t then 50 | heap[t] = nil 51 | assert(not next(t), "A table in the compost heap has been modified!") 52 | end 53 | t = t or {} 54 | return t 55 | end 56 | 57 | 58 | local function reclaim(t, d) 59 | if type(t) ~= "table" then return end 60 | if d and d > 0 then 61 | for i in pairs(t) do 62 | if type(t[i]) == "table" then reclaim(t[i], d - 1) end 63 | end 64 | end 65 | for i in pairs(t) do t[i] = nil end 66 | table_setn(t, 0) 67 | heap[t] = true 68 | end 69 | 70 | ------------------------------------------------------------------------------- 71 | -- Initialization 72 | ------------------------------------------------------------------------------- 73 | 74 | -- Activate a new instance of this library 75 | function activate(self, oldLib, oldDeactivate) 76 | if oldLib then 77 | self.vars = oldLib.vars 78 | if oldLib:IsEventScheduled("UpdateAggroList") then 79 | oldLib:CancelScheduledEvent("UpdateAggroList") 80 | end 81 | end 82 | 83 | RL = AceLibrary("RosterLib-2.0") 84 | roster = RL.roster 85 | playerName = UnitName("player") 86 | self:ScheduleRepeatingEvent("UpdateAggroList", self.UpdateAggroList, 0.2, self) 87 | 88 | if oldDeactivate then oldDeactivate(oldLib) end 89 | end 90 | 91 | ------------------------------------------------------------------------------- 92 | -- Library 93 | ------------------------------------------------------------------------------- 94 | 95 | function lib:UpdateAggroList() 96 | local oldBanzai = acquire() 97 | 98 | if not roster then return end 99 | for i, unit in pairs(roster) do 100 | oldBanzai[unit.unitid] = unit.banzai 101 | 102 | -- deduct aggro for all, increase it later for everyone with aggro 103 | if not unit.banzaiModifier then unit.banzaiModifier = 0 end 104 | unit.banzaiModifier = math.max(0, unit.banzaiModifier - 5) 105 | 106 | -- check for aggro 107 | local targetId = unit.unitid .. "target" 108 | local targetName = UnitName(targetId .. "target") 109 | if roster[targetName] and UnitCanAttack("player", targetId) and UnitCanAttack(targetId, "player") then 110 | if not roster[targetName].banzaiModifier then roster[targetName].banzaiModifier = 0 end 111 | roster[targetName].banzaiModifier = roster[targetName].banzaiModifier + 10 112 | if not roster[targetName].banzaiTarget then roster[targetName].banzaiTarget = acquire() end 113 | table.insert(roster[targetName].banzaiTarget, targetId) 114 | end 115 | 116 | -- cleanup 117 | unit.banzaiModifier = math.max(0, unit.banzaiModifier) 118 | unit.banzaiModifier = math.min(25, unit.banzaiModifier) 119 | 120 | -- set aggro 121 | unit.banzai = (unit.banzaiModifier > 15) 122 | end 123 | 124 | for i, unit in pairs(roster) do 125 | if oldBanzai[unit.unitid] ~= nil and oldBanzai[unit.unitid] ~= unit.banzai then 126 | -- Aggro status has changed. 127 | if unit.banzai == true and unit.banzaiTarget then 128 | -- Unit has aggro 129 | self:TriggerEvent("Banzai_UnitGainedAggro", unit.unitid, unit.banzaiTarget) 130 | if unit.name == playerName then 131 | self:TriggerEvent("Banzai_PlayerGainedAggro", unit.banzaiTarget) 132 | end 133 | elseif unit.banzai == false then 134 | -- Unit lost aggro 135 | self:TriggerEvent("Banzai_UnitLostAggro", unit.unitid) 136 | if unit.name == playerName then 137 | self:TriggerEvent("Banzai_PlayerLostAggro", unit.unitid) 138 | end 139 | end 140 | end 141 | reclaim(unit.banzaiTarget) 142 | unit.banzaiTarget = nil 143 | end 144 | 145 | reclaim(oldBanzai) 146 | oldBanzai = nil 147 | end 148 | 149 | ------------------------------------------------------------------------------- 150 | -- API 151 | ------------------------------------------------------------------------------- 152 | 153 | function lib:GetUnitAggroByUnitId( unitId ) 154 | local rosterUnit = RL:GetUnitObjectFromUnit(unitId) 155 | if not rosterUnit then return nil end 156 | return rosterUnit.banzai 157 | end 158 | 159 | function lib:GetUnitAggroByUnitName( unitName ) 160 | local rosterUnit = RL:GetUnitObjectFromName(unitName) 161 | if not rosterUnit then return nil end 162 | return rosterUnit.banzai 163 | end 164 | 165 | ------------------------------------------------------------------------------- 166 | -- Register 167 | ------------------------------------------------------------------------------- 168 | AceLibrary:Register(lib, MAJOR_VERSION, MINOR_VERSION, activate) 169 | 170 | -------------------------------------------------------------------------------- /libs/Compost-2.0/Compost-2.0.lua: -------------------------------------------------------------------------------- 1 | 2 | --[[ 3 | Name: Compost-2.0 4 | Revision: $Rev: 11579 $ 5 | Author: Tekkub Stoutwrithe (tekkub@gmail.com) 6 | Website: http://wiki.wowace.com/index.php/CompostLib 7 | Documentation: http://wiki.wowace.com/index.php/Compost-2.0_API_Documentation 8 | SVN: svn://svn.wowace.com/root/trunk/CompostLib/Compost-2.0 9 | Description: Recycle tables to reduce garbage generation 10 | Dependencies: AceLibrary 11 | ]] 12 | 13 | local vmajor, vminor = "Compost-2.0", "$Revision: 11579 $" 14 | 15 | if not AceLibrary then error(vmajor .. " requires AceLibrary.") end 16 | if not AceLibrary:IsNewVersion(vmajor, vminor) then return end 17 | 18 | local lib = {} 19 | 20 | local table_setn 21 | do 22 | local version = GetBuildInfo() 23 | if string.find(version, "^2%.") then 24 | -- 2.0.0 25 | table_setn = function() end 26 | else 27 | table_setn = table.setn 28 | end 29 | end 30 | 31 | -- Activate a new instance of this library 32 | local function activate(self, oldLib, oldDeactivate) 33 | if oldLib then -- if upgrading 34 | self.var, self.k = oldLib.var, oldLib.k 35 | else 36 | self.k = { -- Constants go here 37 | maxcache = 10, -- I think this is a good number, I'll change it later if necessary 38 | } 39 | self.var = { -- "Local" variables go here 40 | cache = {}, 41 | secondarycache = {}, 42 | } 43 | 44 | -- This makes the secondary cache table a weak table, any values in it will be reclaimed 45 | -- during a GC if there are no other references to them 46 | setmetatable(self.var.secondarycache, {__mode = "v"}) 47 | end 48 | if not self.var.tablechecks then 49 | self.var.tablechecks = {} 50 | setmetatable(self.var.tablechecks, {__mode = "kv"}) 51 | for i,v in ipairs(self.var.cache) do self.var.tablechecks[v] = true end 52 | for i,v in ipairs(self.var.secondarycache) do self.var.tablechecks[v] = true end 53 | end 54 | if oldDeactivate then oldDeactivate(oldLib) end 55 | end 56 | 57 | 58 | -- Removes an empty table from the cache and returns it 59 | -- or generates a new table if none available 60 | function lib:GetTable() 61 | if self.var.disabled then return {} end 62 | 63 | if table.getn(self.var.cache) > 0 then 64 | for i in pairs(self.var.cache) do 65 | local t = table.remove(self.var.cache, i) 66 | self.var.tablechecks[t] = nil 67 | if next(t) then -- Table has been modified, someone holds a ref still, discard it 68 | error("Someone is modifying tables reclaimed by Compost!") 69 | self:IncDec("numdiscarded", 1) 70 | else -- It's clean, we think... return it. 71 | self:IncDec("totn", -1) 72 | self:IncDec("numrecycled", 1) 73 | return t 74 | end 75 | end 76 | end 77 | 78 | if next(self.var.secondarycache) then 79 | for i in pairs(self.var.secondarycache) do 80 | local t = table.remove(self.var.secondarycache, i) 81 | self.var.tablechecks[t] = nil 82 | if next(t) then -- Table has been modified, someone holds a ref still, discard it 83 | error("Someone is modifying tables reclaimed by Compost!") 84 | self:IncDec("numdiscarded", 1) 85 | else -- It's clean, we think... return it. 86 | self:IncDec("totn", -1) 87 | self:IncDec("numrecycled", 1) 88 | return t 89 | end 90 | end 91 | end 92 | 93 | self:IncDec("numnew", 1) 94 | return {} 95 | end 96 | 97 | 98 | -- Returns a table, populated with any variables passed 99 | -- basically: return {a1, a2, ... a20} 100 | function lib:Acquire(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 101 | local t = self:GetTable() 102 | return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 103 | end 104 | 105 | 106 | -- Acquires a table and fills it with values, hash style 107 | -- basically: return {k1 = v1, k2 = v2, ... k10 = v10} 108 | function lib:AcquireHash(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) 109 | local t = self:GetTable() 110 | return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) 111 | end 112 | 113 | 114 | -- Erases the table passed, fills it with the args passed, and returns it 115 | -- Essentially the same as doing Reclaim then Acquire, except the same table is reused 116 | function lib:Recycle(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 117 | t = self:Erase(t) 118 | return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 119 | end 120 | 121 | 122 | -- Erases the table passed, fills it with the args passed, and returns it 123 | -- Essentially the same as doing Reclaim then AcquireHash, except the same table is reused 124 | function lib:RecycleHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) 125 | t = self:Erase(t) 126 | return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) 127 | end 128 | 129 | 130 | -- Returns a table to the cache 131 | -- All tables referenced inside the passed table will be reclaimed also 132 | -- If a depth is passed, Reclaim will call itsself recursivly 133 | -- to reclaim all tables contained in t to the depth specified 134 | function lib:Reclaim(t, depth) 135 | if type(t) ~= "table" or self.var.disabled then return end 136 | self:assert(not self.var.tablechecks[t], "Cannot reclaim a table twice") 137 | 138 | if not self:ItemsInSecondaryCache() then self.var.totn = table.getn(self.var.cache) end 139 | 140 | if depth and depth > 0 then 141 | for i in pairs(t) do 142 | if type(t[i]) == "table" then self:Reclaim(t[i], depth - 1) end 143 | end 144 | end 145 | self:Erase(t) 146 | if self.k.maxcache and table.getn(self.var.cache) >= self.k.maxcache then 147 | table.insert(self.var.secondarycache, t) 148 | else 149 | table.insert(self.var.cache, t) 150 | end 151 | self:IncDec("numreclaim", 1) 152 | self:IncDec("totn", 1) 153 | self.var.maxn = math.max(self.var.maxn or 0, self.var.totn) 154 | self.var.tablechecks[t] = true 155 | end 156 | 157 | 158 | -- Reclaims multiple tables, can take 10 recursive sets or 20 non-recursives, 159 | -- or any combination of the two. Pass args in the following manner: 160 | -- table1, depth1, tabl2, depth2, table3, table4, table5, depth5, ... 161 | function lib:ReclaimMulti(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 162 | if not a1 then return end 163 | if type(a2) == "number" then 164 | self:Reclaim(a1, a2) 165 | self:ReclaimMulti(a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 166 | else 167 | self:Reclaim(a1) 168 | self:ReclaimMulti(a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 169 | end 170 | end 171 | 172 | 173 | -- Erases the table passed, nothing more nothing less :) 174 | -- Tables referenced inside the passed table are NOT erased 175 | function lib:Erase(t) 176 | if type(t) ~= "table" then return end 177 | if self.var.disabled then return {} end 178 | local mem = gcinfo() 179 | setmetatable(t, nil) 180 | for i in pairs(t) do 181 | t[i] = nil 182 | end 183 | t.reset = 1 184 | t.reset = nil 185 | table_setn(t, 0) 186 | self:IncDec("memfreed", math.abs(gcinfo() - mem)) 187 | self:IncDec("numerased", 1) 188 | return t 189 | end 190 | 191 | 192 | -- Fills the table passed with the args passed 193 | function lib:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20) 194 | if not t then return end 195 | if a1 ~= nil then table.insert(t, a1) end 196 | if a2 ~= nil then table.insert(t, a2) end 197 | if a3 ~= nil then table.insert(t, a3) end 198 | if a4 ~= nil then table.insert(t, a4) end 199 | if a5 ~= nil then table.insert(t, a5) end 200 | if a6 ~= nil then table.insert(t, a6) end 201 | if a7 ~= nil then table.insert(t, a7) end 202 | if a8 ~= nil then table.insert(t, a8) end 203 | if a9 ~= nil then table.insert(t, a9) end 204 | if a10 ~= nil then table.insert(t, a10) end 205 | if a11 ~= nil then table.insert(t, a11) end 206 | if a12 ~= nil then table.insert(t, a12) end 207 | if a13 ~= nil then table.insert(t, a13) end 208 | if a14 ~= nil then table.insert(t, a14) end 209 | if a15 ~= nil then table.insert(t, a15) end 210 | if a16 ~= nil then table.insert(t, a16) end 211 | if a17 ~= nil then table.insert(t, a17) end 212 | if a18 ~= nil then table.insert(t, a18) end 213 | if a19 ~= nil then table.insert(t, a19) end 214 | if a20 ~= nil then table.insert(t, a20) end 215 | return t 216 | end 217 | 218 | 219 | -- Same as Populate, but takes 10 key-value pairs instead 220 | function lib:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10) 221 | if not t then return end 222 | if k1 ~= nil then t[k1] = v1 end 223 | if k2 ~= nil then t[k2] = v2 end 224 | if k3 ~= nil then t[k3] = v3 end 225 | if k4 ~= nil then t[k4] = v4 end 226 | if k5 ~= nil then t[k5] = v5 end 227 | if k6 ~= nil then t[k6] = v6 end 228 | if k7 ~= nil then t[k7] = v7 end 229 | if k8 ~= nil then t[k8] = v8 end 230 | if k9 ~= nil then t[k9] = v9 end 231 | if k10 ~= nil then t[k10] = v10 end 232 | return t 233 | end 234 | 235 | 236 | function lib:IncDec(variable, diff) 237 | self.var[variable] = (self.var[variable] or 0) + diff 238 | end 239 | 240 | 241 | function lib:ItemsInSecondaryCache() 242 | for i in pairs(self.var.secondarycache) do return true end 243 | end 244 | 245 | 246 | function lib:GetSecondaryCacheSize() 247 | local n = 0 248 | for i in pairs(self.var.secondarycache) do n = n + 1 end 249 | return n 250 | end 251 | 252 | 253 | -- Prints out statistics on table recycling 254 | -- /script CompostLib:GetInstance("compost-1"):Stats() 255 | function lib:Stats() 256 | if self.var.disabled then ChatFrame1:AddMessage("CompostLib is disabled!") 257 | else ChatFrame1:AddMessage( 258 | string.format( 259 | "|cff00ff00New: %d|r | |cffffff00Recycled: %d|r | |cff00ffffMain: %d|r | |cffff0000Secondary: %d|r | |cffff8800Max %d|r | |cff888888Erases: %d|r | |cffff00ffMem Saved: %d KiB|r | |cffff0088Lost to GC: %d", 260 | self.var.numnew or 0, 261 | self.var.numrecycled or 0, 262 | table.getn(self.var.cache), 263 | self:GetSecondaryCacheSize(), 264 | self.var.maxn or 0, 265 | (self.var.numerased or 0) - (self.var.numreclaim or 0), 266 | (self.var.memfreed or 0) + 32/1024*(self.var.numrecycled or 0), 267 | (self.var.numreclaim or 0) - (self.var.numrecycled or 0) - table.getn(self.var.cache))) 268 | end 269 | end 270 | 271 | setmetatable(lib, { __call = lib.Acquire }) 272 | 273 | -------------------------------- 274 | -- Load this bitch! -- 275 | -------------------------------- 276 | AceLibrary:Register(lib, vmajor, vminor, activate) 277 | lib = nil 278 | -------------------------------------------------------------------------------- /libs/Deformat-2.0/Deformat-2.0.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Name: Deformat-2.0 3 | Revision: $Rev: 6804 $ 4 | Author(s): ckknight (ckknight@gmail.com) 5 | Website: http://ckknight.wowinterface.com/ 6 | Documentation: http://wiki.wowace.com/index.php/Deformat-2.0 7 | SVN: http://svn.wowace.com/root/trunk/Deformat/Deformat-2.0 8 | Description: A library to deformat format strings. 9 | Dependencies: AceLibrary 10 | ]] 11 | 12 | local MAJOR_VERSION = "Deformat-2.0" 13 | local MINOR_VERSION = "$Revision: 6804 $" 14 | 15 | 16 | if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end 17 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end 18 | 19 | local Deformat = {} 20 | 21 | do 22 | local sequences = { 23 | ["%d*d"] = "%%-?%%d+", 24 | ["s"] = ".+", 25 | ["[fg]"] = "%%-?%%d+%%.%%d+", 26 | ["%%%.%d[fg]"] = "%%-?%%d+%%.?%%d*", 27 | ["c"] = ".", 28 | } 29 | local curries = {} 30 | 31 | local function doNothing(item) 32 | return item 33 | end 34 | local v = {} 35 | 36 | local function concat(a1, a2, a3, a4, a5) 37 | local left, right 38 | if not a2 then 39 | return a1 40 | elseif not a3 then 41 | left, right = a1, a2 42 | elseif not a4 then 43 | return concat(concat(a1, a2), a3) 44 | elseif not a5 then 45 | return concat(concat(concat(a1, a2), a3), a4) 46 | else 47 | return concat(concat(concat(concat(a1, a2), a3), a4), a5) 48 | end 49 | if not string.find(left, "%%1%$") and not string.find(right, "%%1%$") then 50 | return left .. right 51 | elseif not string.find(right, "%%1%$") then 52 | local i 53 | for j = 9, 1, -1 do 54 | if string.find(left, "%%" .. j .. "%$") then 55 | i = j 56 | break 57 | end 58 | end 59 | while true do 60 | local first 61 | local firstPat 62 | for x, y in pairs(sequences) do 63 | local i = string.find(right, "%%" .. x) 64 | if not first or (i and i < first) then 65 | first = i 66 | firstPat = x 67 | end 68 | end 69 | if not first then 70 | break 71 | end 72 | i = i + 1 73 | right = string.gsub(right, "%%(" .. firstPat .. ")", "%%" .. i .. "$%1") 74 | end 75 | return left .. right 76 | elseif not string.find(left, "%%1%$") then 77 | local i = 1 78 | while true do 79 | local first 80 | local firstPat 81 | for x, y in pairs(sequences) do 82 | local i = string.find(left, "%%" .. x) 83 | if not first or (i and i < first) then 84 | first = i 85 | firstPat = x 86 | end 87 | end 88 | if not first then 89 | break 90 | end 91 | i = i + 1 92 | left = string.gsub(left, "%%(" .. firstPat .. ")", "%%" .. i .. "$%1") 93 | end 94 | return concat(left, right) 95 | else 96 | local i 97 | for j = 9, 1, -1 do 98 | if string.find(left, "%%" .. j .. "%$") then 99 | i = j 100 | break 101 | end 102 | end 103 | local j 104 | for k = 9, 1, -1 do 105 | if string.find(right, "%%" .. k .. "%$") then 106 | j = k 107 | break 108 | end 109 | end 110 | for k = j, 1, -1 do 111 | right = string.gsub(right, "%%" .. k .. "%$", "%%" .. k + i .. "%$") 112 | end 113 | return left .. right 114 | end 115 | end 116 | 117 | local function Curry(a1, a2, a3, a4, a5) 118 | local pattern = concat(a1, a2, a3, a4, a5) 119 | if not string.find(pattern, "%%1%$") then 120 | local unpattern = string.gsub(pattern, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") 121 | local f = {} 122 | local i = 0 123 | while true do 124 | local first 125 | local firstPat 126 | for x, y in pairs(sequences) do 127 | local i = string.find(unpattern, "%%%%" .. x) 128 | if not first or (i and i < first) then 129 | first = i 130 | firstPat = x 131 | end 132 | end 133 | if not first then 134 | break 135 | end 136 | unpattern = string.gsub(unpattern, "%%%%" .. firstPat, "(" .. sequences[firstPat] .. ")", 1) 137 | i = i + 1 138 | if firstPat == "c" or firstPat == "s" then 139 | table.insert(f, doNothing) 140 | else 141 | table.insert(f, tonumber) 142 | end 143 | end 144 | unpattern = "^" .. unpattern .. "$" 145 | local _,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india 146 | if i == 0 then 147 | return 148 | elseif i == 1 then 149 | return function(text) 150 | _,_,alpha = string.find(text, unpattern) 151 | if alpha then 152 | return f[1](alpha) 153 | end 154 | end 155 | elseif i == 2 then 156 | return function(text) 157 | _,_,alpha, bravo = string.find(text, unpattern) 158 | if alpha then 159 | return f[1](alpha), f[2](bravo) 160 | end 161 | end 162 | elseif i == 3 then 163 | return function(text) 164 | _,_,alpha, bravo, charlie = string.find(text, unpattern) 165 | if alpha then 166 | return f[1](alpha), f[2](bravo), f[3](charlie) 167 | end 168 | end 169 | elseif i == 4 then 170 | return function(text) 171 | _,_,alpha, bravo, charlie, delta = string.find(text, unpattern) 172 | if alpha then 173 | return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta) 174 | end 175 | end 176 | elseif i == 5 then 177 | return function(text) 178 | _,_,alpha, bravo, charlie, delta, echo = string.find(text, unpattern) 179 | if alpha then 180 | return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo) 181 | end 182 | end 183 | elseif i == 6 then 184 | return function(text) 185 | _,_,alpha, bravo, charlie, delta, echo, foxtrot = string.find(text, unpattern) 186 | if alpha then 187 | return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot) 188 | end 189 | end 190 | elseif i == 7 then 191 | return function(text) 192 | _,_,alpha, bravo, charlie, delta, echo, foxtrot, golf = string.find(text, unpattern) 193 | if alpha then 194 | return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf) 195 | end 196 | end 197 | elseif i == 8 then 198 | return function(text) 199 | _,_,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel = string.find(text, unpattern) 200 | if alpha then 201 | return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf), f[8](hotel) 202 | end 203 | end 204 | else 205 | return function(text) 206 | _,_,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india = string.find(text, unpattern) 207 | if alpha then 208 | return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf), f[8](hotel), f[9](india) 209 | end 210 | end 211 | end 212 | else 213 | local o = {} 214 | local f = {} 215 | local unpattern = string.gsub(pattern, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") 216 | local i = 1 217 | while true do 218 | local pat 219 | for x, y in pairs(sequences) do 220 | if not pat and string.find(unpattern, "%%%%" .. i .. "%%%$" .. x) then 221 | pat = x 222 | break 223 | end 224 | end 225 | if not pat then 226 | break 227 | end 228 | unpattern = string.gsub(unpattern, "%%%%" .. i .. "%%%$" .. pat, "(" .. sequences[pat] .. ")", 1) 229 | if pat == "c" or pat == "s" then 230 | table.insert(f, doNothing) 231 | else 232 | table.insert(f, tonumber) 233 | end 234 | i = i + 1 235 | end 236 | i = 1 237 | string.gsub(pattern, "%%(%d)%$", function(w) o[i] = tonumber(w); i = i + 1; end) 238 | v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9] = nil 239 | for x, y in pairs(f) do 240 | v[x] = f[y] 241 | end 242 | for x, y in pairs(v) do 243 | f[x] = v[x] 244 | end 245 | unpattern = "^" .. unpattern .. "$" 246 | i = i - 1 247 | if i == 0 then 248 | return function(text) 249 | return 250 | end 251 | elseif i == 1 then 252 | return function(text) 253 | _,_,v[1] = string.find(text, unpattern) 254 | if v[1] then 255 | return f[1](v[1]) 256 | end 257 | end 258 | elseif i == 2 then 259 | return function(text) 260 | _,_,v[1],v[2] = string.find(text, unpattern) 261 | if v[1] then 262 | return f[1](v[o[1]]), f[2](v[o[2]]) 263 | end 264 | end 265 | elseif i == 3 then 266 | return function(text) 267 | _,_,v[1],v[2],v[3] = string.find(text, unpattern) 268 | if v[1] then 269 | return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]) 270 | end 271 | end 272 | elseif i == 4 then 273 | return function(text) 274 | _,_,v[1],v[2],v[3],v[4] = string.find(text, unpattern) 275 | if v[1] then 276 | return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]) 277 | end 278 | end 279 | elseif i == 5 then 280 | return function(text) 281 | _,_,v[1],v[2],v[3],v[4],v[5] = string.find(text, unpattern) 282 | if v[1] then 283 | return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]) 284 | end 285 | end 286 | elseif i == 6 then 287 | return function(text) 288 | _,_,v[1],v[2],v[3],v[4],v[5],v[6] = string.find(text, unpattern) 289 | if v[1] then 290 | return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]) 291 | end 292 | end 293 | elseif i == 7 then 294 | return function(text) 295 | _,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7] = string.find(text, unpattern) 296 | if v[1] then 297 | return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]]) 298 | end 299 | end 300 | elseif i == 8 then 301 | return function(text) 302 | _,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8] = string.find(text, unpattern) 303 | if v[1] then 304 | return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]]), f[8](v[o[8]]) 305 | end 306 | end 307 | else 308 | return function(text) 309 | _,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9] = string.find(text, unpattern) 310 | if v[1] then 311 | return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]]), f[8](v[o[8]]), f[9](v[o[9]]) 312 | end 313 | end 314 | end 315 | end 316 | end 317 | 318 | function Deformat:Deformat(text, a1, a2, a3, a4, a5) 319 | self:argCheck(text, 2, "string") 320 | self:argCheck(a1, 3, "string") 321 | local pattern = a1 322 | if a5 then 323 | pattern = a1 .. a2 .. a3 .. a4 .. a5 324 | elseif a4 then 325 | pattern = a1 .. a2 .. a3 .. a4 326 | elseif a3 then 327 | pattern = a1 .. a2 .. a3 328 | elseif a2 then 329 | pattern = a1 .. a2 330 | end 331 | if curries[pattern] == nil then 332 | curries[pattern] = Curry(a1, a2, a3, a4, a5) 333 | end 334 | return curries[pattern](text) 335 | end 336 | end 337 | 338 | local mt = getmetatable(Deformat) or {} 339 | mt.__call = Deformat.Deformat 340 | setmetatable(Deformat, mt) 341 | 342 | AceLibrary:Register(Deformat, MAJOR_VERSION, MINOR_VERSION) 343 | Deformat = nil 344 | -------------------------------------------------------------------------------- /libs/Gratuity-2.0/Gratuity-2.0.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Name: Gratuity-2.0 3 | Revision: $Rev: 11053 $ 4 | Author: Tekkub Stoutwrithe (tekkub@gmail.com) 5 | Website: http://wiki.wowace.com/index.php/GratuityLib 6 | Documentation: http://wiki.wowace.com/index.php/Gratuity-2.0_API_Documentation 7 | SVN: svn://svn.wowace.com/root/trunk/GratuityLib/Gratuity-2.0 8 | Description: Tooltip parsing library 9 | Dependencies: AceLibrary, (optional) Compost-2.0, (optional) Deformat-2.0 10 | ]] 11 | 12 | local vmajor, vminor = "Gratuity-2.0", "$Revision: 11053 $" 13 | 14 | if not AceLibrary then error(vmajor .. " requires AceLibrary.") end 15 | if not AceLibrary:IsNewVersion(vmajor, vminor) then return end 16 | 17 | local lib = {} 18 | local methods = { 19 | "SetBagItem", "SetAction", "SetAuctionItem", "SetAuctionSellItem", "SetBuybackItem", 20 | "SetCraftItem", "SetCraftSpell", "SetHyperlink", "SetInboxItem", "SetInventoryItem", 21 | "SetLootItem", "SetLootRollItem", "SetMerchantItem", "SetPetAction", "SetPlayerBuff", 22 | "SetQuestItem", "SetQuestLogItem", "SetQuestRewardSpell", "SetSendMailItem", "SetShapeshift", 23 | "SetSpell", "SetTalent", "SetTrackingSpell", "SetTradePlayerItem", "SetTradeSkillItem", "SetTradeTargetItem", 24 | "SetTrainerService", "SetUnit", "SetUnitBuff", "SetUnitDebuff", 25 | } 26 | 27 | 28 | -- Activate a new instance of this library 29 | local function activate(self, oldLib, oldDeactivate) 30 | if oldLib then self.vars = oldLib.vars 31 | else 32 | self.vars = {} 33 | self:CreateTooltip() 34 | end 35 | 36 | self:CreateSetMethods() 37 | 38 | if oldDeactivate then oldDeactivate(oldLib) end 39 | end 40 | 41 | 42 | function lib:InitCompost() 43 | if not self.vars.compost and AceLibrary:HasInstance("Compost-2.0") then self.vars.compost = AceLibrary("Compost-2.0") end 44 | end 45 | 46 | 47 | function lib:CreateTooltip() 48 | local tt = CreateFrame("GameTooltip") 49 | 50 | self.vars.tooltip = tt 51 | tt:SetOwner(tt, "ANCHOR_NONE") 52 | -- tooltip:SetParent() 53 | 54 | self.vars.Llines, self.vars.Rlines = {}, {} 55 | for i=1,30 do 56 | self.vars.Llines[i], self.vars.Rlines[i] = tt:CreateFontString(), tt:CreateFontString() 57 | self.vars.Llines[i]:SetFontObject(GameFontNormal) 58 | self.vars.Rlines[i]:SetFontObject(GameFontNormal) 59 | tt:AddFontStrings(self.vars.Llines[i], self.vars.Rlines[i]) 60 | end 61 | end 62 | 63 | 64 | -- Clears the tooltip completely, none of this "erase left, hide right" crap blizzard does 65 | function lib:Erase() 66 | self.vars.tooltip:ClearLines() -- Ensures tooltip's NumLines is reset 67 | for i=1,30 do self.vars.Rlines[i]:SetText() end -- Clear text from right side (ClearLines only hides them) 68 | if not self.vars.tooltip:IsOwned(self.vars.tooltip) then self.vars.tooltip:SetOwner(self.vars.tooltip, "ANCHOR_NONE") end 69 | self:assert(self.vars.tooltip:IsOwned(self.vars.tooltip), "Gratuity's tooltip is not scanable") 70 | end 71 | 72 | 73 | -- Get the number of lines 74 | -- Arg: endln - If passed and tooltip's NumLines is higher, endln is returned back 75 | function lib:NumLines(endln) 76 | local num = self.vars.tooltip:NumLines() 77 | return endln and num > endln and endln or num or 0 78 | end 79 | 80 | local FindDefault = function(str, pattern) 81 | return string.find(str, pattern); 82 | end; 83 | 84 | local FindExact = function(str, pattern) 85 | if (str == pattern) then 86 | return string.find(str, pattern); 87 | end; 88 | end; 89 | 90 | -- If text is found on tooltip then results of string.find are returned 91 | -- Args: 92 | -- txt - The text string to find 93 | -- startln - First tooltip line to check, default 1 94 | -- endln - Last line to test, default 30 95 | -- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored 96 | -- exact - the compare will be an exact match vs the default behaviour of 97 | function lib:Find(txt, startln, endln, ignoreleft, ignoreright, exact) 98 | local searchFunction = FindDefault; 99 | if (exact == true) then 100 | searchFunction = FindExact; 101 | end; 102 | self:argCheck(txt, 2, "string", "number") 103 | local t1, t2 = type(startln or 1), type(self:NumLines(endln)) 104 | if (t1 ~= "number" or t2 ~= "number") then print(t1, t2, (startln or 1),self:NumLines(endln)) end 105 | for i=(startln or 1),self:NumLines(endln) do 106 | if not ignoreleft then 107 | local txtl = self.vars.Llines[i]:GetText() 108 | if (txtl and searchFunction(txtl, txt)) then return string.find(txtl, txt) end 109 | end 110 | 111 | if not ignoreright then 112 | local txtr = self.vars.Rlines[i]:GetText() 113 | if (txtr and searchFunction(txtr, txt)) then return string.find(txtr, txt) end 114 | end 115 | end 116 | end 117 | 118 | 119 | -- Calls Find many times. 120 | -- Args are passed directly to Find, t1-t10 replace the txt arg 121 | -- Returns Find results for the first match found, if any 122 | function lib:MultiFind(startln, endln, ignoreleft, ignoreright, t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) 123 | self:argCheck(t1, 6, "string", "number") 124 | if t1 and self:Find(t1, startln, endln, ignoreleft, ignoreright) then return self:Find(t1, startln, endln, ignoreleft, ignoreright) 125 | elseif t2 then return self:MultiFind(startln, endln, ignoreleft, ignoreright, t2,t3,t4,t5,t6,t7,t8,t9,t10) end 126 | end 127 | 128 | 129 | local deformat 130 | -- If text is found on tooltip then results of deformat:Deformat are returned 131 | -- Args: 132 | -- txt - The text string to deformat and serach for 133 | -- startln - First tooltip line to check, default 1 134 | -- endln - Last line to test, default 30 135 | -- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored 136 | function lib:FindDeformat(txt, startln, endln, ignoreleft, ignoreright) 137 | self:argCheck(txt, 2, "string", "number") 138 | if not deformat then 139 | self:assert(AceLibrary:HasInstance("Deformat-2.0"), "FindDeformat requires Deformat-2.0 to be available") 140 | deformat = AceLibrary("Deformat-2.0") 141 | end 142 | 143 | for i=(startln or 1),self:NumLines(endln) do 144 | if not ignoreleft then 145 | local txtl = self.vars.Llines[i]:GetText() 146 | if (txtl and deformat(txtl, txt)) then return deformat(txtl, txt) end 147 | end 148 | 149 | if not ignoreright then 150 | local txtr = self.vars.Rlines[i]:GetText() 151 | if (txtr and deformat(txtr, txt)) then return deformat(txtr, txt) end 152 | end 153 | end 154 | end 155 | 156 | 157 | -- Returns a table of strings pulled from the tooltip, or nil if no strings in tooltip 158 | -- Args: 159 | -- startln - First tooltip line to check, default 1 160 | -- endln - Last line to test, default 30 161 | -- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored 162 | function lib:GetText(startln, endln, ignoreleft, ignoreright) 163 | self:InitCompost() 164 | local retval 165 | 166 | for i=(startln or 1),(endln or 30) do 167 | local txtl, txtr 168 | if not ignoreleft then txtl = self.vars.Llines[i]:GetText() end 169 | if not ignoreright then txtr = self.vars.Rlines[i]:GetText() end 170 | if txtl or txtr then 171 | if not retval then retval = self.vars.compost and self.vars.compost:Acquire() or {} end 172 | local t = self.vars.compost and self.vars.compost:Acquire(txtl, txtr) or {txtl, txtr} 173 | table.insert(retval, t) 174 | end 175 | end 176 | 177 | return retval 178 | end 179 | 180 | 181 | -- Returns the text from a specific line (both left and right unless second arg is true) 182 | -- Args: 183 | -- line - the line number you wish to retrieve 184 | -- getright - if passed the right line will be returned, if not the left will be returned 185 | function lib:GetLine(line, getright) 186 | self:argCheck(line, 2, "number") 187 | if self.vars.tooltip:NumLines() < line then return end 188 | if getright then return self.vars.Rlines[line] and self.vars.Rlines[line]:GetText() 189 | elseif self.vars.Llines[line] then 190 | return self.vars.Llines[line]:GetText(), self.vars.Rlines[line]:GetText() 191 | end 192 | end 193 | 194 | 195 | ----------------------------------- 196 | -- Set tooltip methods -- 197 | ----------------------------------- 198 | 199 | -- These methods are designed to immitate the GameTooltip API 200 | local testmethods = { 201 | SetAction = function(id) return HasAction(id) end, 202 | } 203 | local gettrue = function() return true end 204 | function lib:CreateSetMethods() 205 | for _,m in pairs(methods) do 206 | local meth = m 207 | local func = testmethods[meth] or gettrue 208 | self[meth] = function(self,a1,a2,a3,a4) 209 | self:Erase() 210 | if not func(a1,a2,a3,a4) then return end 211 | return self:pcall(self.vars.tooltip[meth], self.vars.tooltip,a1,a2,a3,a4) end 212 | end 213 | end 214 | 215 | 216 | -------------------------------- 217 | -- Load this bitch! -- 218 | -------------------------------- 219 | AceLibrary:Register(lib, vmajor, vminor, activate) 220 | lib = nil 221 | -------------------------------------------------------------------------------- /libs/ItemBonusLib-1.0/ItemBonusLib-1.0.lua: -------------------------------------------------------------------------------- 1 | local MAJOR_VERSION = "ItemBonusLib-1.0" 2 | local MINOR_VERSION = "$Revision: 17465 $" 3 | 4 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end 5 | 6 | if not AceLibrary:HasInstance("AceLocale-2.2") then error(MAJOR_VERSION .. " requires AceLocale-2.2") end 7 | if not AceLibrary:HasInstance("Gratuity-2.0") then error(MAJOR_VERSION .. " requires Gratuity-2.0") end 8 | if not AceLibrary:HasInstance("Deformat-2.0") then error(MAJOR_VERSION .. " requires Deformat-2.0") end 9 | 10 | local DEBUG = false 11 | 12 | local ItemBonusLib = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceConsole-2.0", "AceDebug-2.0") 13 | ItemBonusLib:SetDebugging(DEBUG) 14 | 15 | local Gratuity = AceLibrary("Gratuity-2.0") 16 | local Deformat = AceLibrary("Deformat-2.0") 17 | 18 | local L = AceLibrary("AceLocale-2.2"):new("ItemBonusLib") 19 | 20 | -- bonuses[BONUS] = VALUE 21 | local bonuses = {} 22 | 23 | -- details[BONUS][SLOT] = VALUE 24 | local details = {} 25 | 26 | -- items[LINK].bonuses[BONUS] = VALUE 27 | -- items[LINK].set = SETNAME 28 | -- items[LINK].set_line = number 29 | local items = {} 30 | 31 | -- sets[SETNAME].count = COUNT 32 | -- sets[SETNAME].bonuses[NUM][BONUS] = VALUE 33 | -- sets[SETNAME].scan_count = COUNT 34 | -- sets[SETNAME].scan_bonuses = COUNT 35 | local sets = {} 36 | 37 | local slots = { 38 | ["Head"] = true, 39 | ["Neck"] = true, 40 | ["Shoulder"] = true, 41 | ["Shirt"] = true, 42 | ["Chest"] = true, 43 | ["Waist"] = true, 44 | ["Legs"] = true, 45 | ["Feet"] = true, 46 | ["Wrist"] = true, 47 | ["Hands"] = true, 48 | ["Finger0"] = true, 49 | ["Finger1"] = true, 50 | ["Trinket0"] = true, 51 | ["Trinket1"] = true, 52 | ["Back"] = true, 53 | ["MainHand"] = true, 54 | ["SecondaryHand"] = true, 55 | ["Ranged"] = true, 56 | ["Tabard"] = true, 57 | } 58 | 59 | function ItemBonusLib:OnInitialize() 60 | self:RegisterEvent("PLAYER_ENTERING_WORLD") 61 | self:RegisterEvent("PLAYER_LEAVING_WORLD") 62 | for s in pairs(slots) do 63 | slots[s] = GetInventorySlotInfo (s.."Slot") 64 | end 65 | 66 | local options = { 67 | type = "group", 68 | desc = L["An addon to get information about bonus from equipped items"], 69 | args = { 70 | show = { 71 | type = "execute", 72 | name = L["show"], 73 | desc = L["Show all bonuses from the current equipment"], 74 | func = function () 75 | self:Print(L["Current equipment bonuses:"]) 76 | for bonus, value in pairs(bonuses) do 77 | self:Print("%s : %d", self:GetBonusFriendlyName(bonus), value) 78 | end 79 | end 80 | }, 81 | details = { 82 | type = "execute", 83 | name = L["details"], 84 | desc = L["Shows bonuses with slot distribution"], 85 | func = function () 86 | self:Print(L["Current equipment bonus details:"]) 87 | for bonus, detail in pairs(details) do 88 | local s = {} 89 | for slot, value in pairs(detail) do 90 | table.insert(s, string.format("%s : %d", slot, value)) 91 | end 92 | self:Print("%s : %d (%s)", self:GetBonusFriendlyName(bonus), bonuses[bonus], table.concat(s, ", ")) 93 | end 94 | end 95 | }, 96 | item = { 97 | type = "text", 98 | name = L["item"], 99 | desc = L["show bonuses of given itemlink"], 100 | usage = L[""], 101 | get = false, 102 | set = function (link) 103 | local info = self:ScanItemLink(link) 104 | self:Print(L["Bonuses for %s:"], link) 105 | for bonus, value in pairs(info.bonuses) do 106 | self:Print("%s : %d", self:GetBonusFriendlyName(bonus), value) 107 | end 108 | if info.set then 109 | self:Print(L["Item is part of set [%s]"], info.set) 110 | local set = sets[info.set] 111 | for number, bonuses in pairs(set.bonuses) do 112 | local has_bonus = number <= set.count and "*" or " " 113 | self:Print(L[" %sBonus for %d pieces :"], has_bonus, number) 114 | for bonus, value in pairs(bonuses) do 115 | self:Print(" %s : %d", self:GetBonusFriendlyName(bonus), value) 116 | end 117 | end 118 | end 119 | end 120 | }, 121 | slot = { 122 | type = "text", 123 | name = L["slot"], 124 | desc = L["show bonuses of given slot"], 125 | usage = L[""], 126 | get = false, 127 | set = function (slot) 128 | self:Print(L["Bonuses of slot %s:"], slot) 129 | for bonus, detail in pairs(details) do 130 | if detail[slot] then 131 | self:Print("%s : %d", self:GetBonusFriendlyName(bonus), detail[slot]) 132 | end 133 | end 134 | end 135 | }, 136 | }, 137 | } 138 | 139 | self:RegisterChatCommand(L.CHAT_COMMANDS, options) 140 | 141 | end 142 | 143 | function ItemBonusLib:PLAYER_ENTERING_WORLD() 144 | self:RegisterBucketEvent("UNIT_INVENTORY_CHANGED", 0.5) 145 | self:ScheduleEvent(function() self:ScanEquipment() end, 1) 146 | end 147 | 148 | function ItemBonusLib:PLAYER_LEAVING_WORLD() 149 | self:UnregisterBucketEvent("UNIT_INVENTORY_CHANGED") 150 | end 151 | 152 | function ItemBonusLib:UNIT_INVENTORY_CHANGED(units) 153 | if units.player then 154 | self:ScanEquipment() 155 | end 156 | end 157 | 158 | local cleanItemLink 159 | do 160 | local s = string 161 | local trim = function (str) 162 | local gsub = s.gsub 163 | str = gsub (str, "^%s+", "" ) 164 | str = gsub (str, "%s+$", "" ) 165 | str = gsub (str, "%.$", "" ) 166 | return str 167 | end 168 | 169 | local equip = ITEM_SPELL_TRIGGER_ONEQUIP 170 | local l_equip = s.len(equip) 171 | 172 | function cleanItemLink(itemLink) 173 | local _, _, link = s.find(itemLink, "|c%x+|H(item:%d+:%d+:%d+:%d+)|h%[.-%]|h|r") 174 | return link or itemLink 175 | end 176 | 177 | function ItemBonusLib:AddValue(bonuses, effect, value) 178 | if type(effect) == "string" then 179 | bonuses[effect] = (bonuses[effect] or 0) + value 180 | elseif type(value) == "table" then 181 | for i, e in ipairs(effect) do 182 | self:AddValue (bonuses, e, value[i]) 183 | end 184 | else 185 | for _, e in ipairs(effect) do 186 | self:AddValue (bonuses, e, value) 187 | end 188 | end 189 | end 190 | 191 | function ItemBonusLib:CheckPassive(bonuses, line) 192 | for _, p in pairs(L.PATTERNS_PASSIVE) do 193 | local _, _, value = s.find (line, "^" .. p.pattern) 194 | if value then 195 | self:AddValue (bonuses, p.effect, value) 196 | return true 197 | end 198 | end 199 | end 200 | 201 | function ItemBonusLib:CheckToken(bonuses, token, value) 202 | local t = L.PATTERNS_GENERIC_LOOKUP[token] 203 | if t then 204 | self:AddValue (bonuses, t, value) 205 | return true 206 | else 207 | local s1, s2 208 | 209 | for _, p in ipairs(L.PATTERNS_GENERIC_STAGE1) do 210 | if s.find (token, p.pattern, 1, 1) then 211 | s1 = p.effect 212 | break 213 | end 214 | end 215 | for _, p in ipairs(L.PATTERNS_GENERIC_STAGE2) do 216 | if s.find(token, p.pattern, 1, 1) then 217 | s2 = p.effect 218 | break 219 | end 220 | end 221 | if s1 and s2 then 222 | self:AddValue (bonuses, s1..s2, value) 223 | return true 224 | end 225 | end 226 | self:Debug("CheckToken failed for \"%s\" (%d)", token, value) 227 | end 228 | 229 | function ItemBonusLib:CheckGeneric(bonuses, line) 230 | local found 231 | 232 | while s.len(line) > 0 do 233 | local tmpStr 234 | local pos = s.find (line, "/", 1, true) 235 | if pos then 236 | tmpStr = s.sub (line, 1, pos-1) 237 | line = s.sub (line, pos+1) 238 | else 239 | tmpStr = line 240 | line = "" 241 | end 242 | 243 | -- trim line 244 | tmpStr = trim (tmpStr) 245 | 246 | local _, _, value, token = s.find(tmpStr, "^%+(%d+)%%?(.*)$") 247 | if not value then 248 | _, _, token, value = s.find(tmpStr, "^(.*)%+(%d+)%%?$") 249 | end 250 | if token and value then 251 | -- trim token 252 | token = trim (token) 253 | if self:CheckToken (bonuses, token, value) then 254 | found = true 255 | end 256 | end 257 | end 258 | return found 259 | end 260 | 261 | function ItemBonusLib:CheckOther(bonuses, line) 262 | for _, p in ipairs(L.PATTERNS_OTHER) do 263 | local start, _, value = s.find (line, "^" .. p.pattern) 264 | if start then 265 | if p.value then 266 | self:AddValue(bonuses, p.effect, p.value) 267 | elseif value then 268 | self:AddValue (bonuses, p.effect, value) 269 | end 270 | return true 271 | end 272 | end 273 | end 274 | 275 | function ItemBonusLib:AddBonusInfo(bonuses, line, no_prefix) 276 | local found 277 | if no_prefix then 278 | found = self:CheckPassive(bonuses, line) 279 | elseif s.sub (line, 0, l_equip) == equip then 280 | found = self:CheckPassive (bonuses, s.sub(line, l_equip + 2)) 281 | end 282 | if not found then 283 | found = self:CheckGeneric(bonuses, line) 284 | if not found then 285 | found = self:CheckOther(bonuses, line) 286 | if not found then 287 | self:Debug("Unmatched bonus line \"%s\"", line) 288 | end 289 | end 290 | end 291 | end 292 | end 293 | 294 | do 295 | local ITEM_SET_NAME = ITEM_SET_NAME 296 | local ITEM_SET_BONUS = ITEM_SET_BONUS 297 | local ITEM_SET_BONUS_GRAY = ITEM_SET_BONUS_GRAY 298 | 299 | function ItemBonusLib:ScanItemLink(link) 300 | link = cleanItemLink(link) 301 | local info = items[link] 302 | local scan_set 303 | local set_name, set_count, set_total 304 | if not info then 305 | info = { bonuses = {} } 306 | Gratuity:SetHyperlink(link) 307 | for i = 2, Gratuity:NumLines() do 308 | local line = Gratuity:GetLine(i) 309 | set_name, set_count, set_total = Deformat(line, ITEM_SET_NAME) 310 | if set_name then 311 | info.set = set_name 312 | info.set_line = i 313 | local set = sets[set_name] 314 | if not set or set.scan_count > set_count and set.scan_bonuses > 1 then 315 | scan_set = true 316 | end 317 | break 318 | end 319 | self:AddBonusInfo(info.bonuses, line) 320 | end 321 | items[link] = info 322 | elseif info.set then 323 | Gratuity:SetHyperlink(link) 324 | set_name, set_count, set_total = Deformat(Gratuity:GetLine(info.set_line), ITEM_SET_NAME) 325 | local set = sets[set_name] 326 | if set.scan_count > set_count and set.scan_bonuses > 1 then 327 | scan_set = true 328 | end 329 | end 330 | if scan_set then 331 | self:Debug("Scanning set \"%s\"", set_name) 332 | local set = { count = 0, bonuses = {}, scan_count = set_count, scan_bonuses = 0 } 333 | for i = info.set_line + set_total + 2, Gratuity:NumLines() do 334 | local line = Gratuity:GetLine(i) 335 | local count, bonus 336 | local bonus = Deformat(line, ITEM_SET_BONUS) 337 | if bonus then 338 | set.scan_bonuses = set.scan_bonuses + 1 339 | count = set_count 340 | else 341 | count, bonus = Deformat( 342 | line, ITEM_SET_BONUS_GRAY) 343 | end 344 | if not bonus then 345 | self:Debug("Invalid set line \"%s\"", line) 346 | -- break 347 | else 348 | local bonuses = set.bonuses[count] or {} 349 | self:AddBonusInfo(bonuses, bonus, true) 350 | set.bonuses[count] = bonuses 351 | end 352 | end 353 | sets[set_name] = set 354 | end 355 | return info 356 | end 357 | end 358 | 359 | function ItemBonusLib:ScanEquipment() 360 | -- clean bonus information 361 | for bonus in pairs(bonuses) do 362 | bonuses[bonus] = nil 363 | end 364 | for bonus, detail in pairs(details) do 365 | for slot in pairs(detail) do 366 | detail[slot] = nil 367 | end 368 | end 369 | for _, set in pairs(sets) do 370 | set.count = 0 371 | end 372 | 373 | for slot, id in pairs(slots) do 374 | local link = GetInventoryItemLink("player", id) 375 | if link then 376 | self:Debug("Scanning item %s", link) 377 | local info = self:ScanItemLink(link) 378 | local set = info.set 379 | if set then 380 | sets[set].count = sets[set].count + 1 381 | end 382 | for bonus, value in pairs(info.bonuses) do 383 | bonuses[bonus] = (bonuses[bonus] or 0) + value 384 | if not details[bonus] then 385 | details[bonus] = {} 386 | end 387 | details[bonus][slot] = (details[bonus][slot] or 0) + value 388 | end 389 | end 390 | end 391 | for _, set in pairs(sets) do 392 | for i = 2, set.count do 393 | if set.bonuses[i] then 394 | for bonus, value in pairs(set.bonuses[i]) do 395 | bonuses[bonus] = (bonuses[bonus] or 0) + value 396 | if not details[bonus] then 397 | details[bonus] = {} 398 | end 399 | details[bonus].Set = (details[bonus].Set or 0) + value 400 | end 401 | end 402 | end 403 | end 404 | self:TriggerEvent("ItemBonusLib_Update") 405 | end 406 | 407 | -- DEBUG 408 | if DEBUG then 409 | function ItemBonusLib:DumpCachedItems(clear) 410 | DevTools_Dump(items) 411 | if clear then 412 | items = {} 413 | end 414 | end 415 | 416 | function ItemBonusLib:DumpCachedSets(clear) 417 | DevTools_Dump(sets) 418 | end 419 | 420 | function ItemBonusLib:DumpBonuses() 421 | DevTools_Dump(bonuses) 422 | end 423 | 424 | function ItemBonusLib:DumpDetails() 425 | DevTools_Dump(details) 426 | end 427 | 428 | function ItemBonusLib:Reload() 429 | items = {} 430 | sets = {} 431 | self:ScanEquipment() 432 | end 433 | end 434 | 435 | -- BonusScanner compatible API 436 | function ItemBonusLib:GetBonus(bonus) 437 | return bonuses[bonus] or 0 438 | end 439 | 440 | function ItemBonusLib:GetSlotBonuses (slotname) 441 | local bonuses = {} 442 | for bonus, detail in pairs(details) do 443 | if detail[slotname] then 444 | bonuses[bonus] = detail[slotname] 445 | end 446 | end 447 | return bonuses 448 | end 449 | 450 | function ItemBonusLib:GetBonusDetails (bonus) 451 | return details[bonus] or {} 452 | end 453 | 454 | function ItemBonusLib:GetSlotBonus (bonus, slotname) 455 | local detail = details[bonus] 456 | return detail and detail[slotname] or 0 457 | end 458 | 459 | function ItemBonusLib:GetBonusFriendlyName (bonus) 460 | return L.NAMES[bonus] or bonus 461 | end 462 | 463 | function ItemBonusLib:IsActive () 464 | return true 465 | end 466 | 467 | function ItemBonusLib:ScanItem (itemlink, excludeSet) 468 | if not excludeSet then 469 | self:error("excludeSet can't be false on BonusScanner compatible API") 470 | end 471 | local name, link = GetItemInfo(itemlink) 472 | if not name then 473 | return 474 | end 475 | return self:ScanItemLink(link).bonuses 476 | end 477 | 478 | function ItemBonusLib:ScanTooltipFrame (frame, excludeSet) 479 | self:error("BonusScanner:ScanTooltipFrame() is not available") 480 | end 481 | 482 | AceLibrary:Register(ItemBonusLib, MAJOR_VERSION, MINOR_VERSION) 483 | -------------------------------------------------------------------------------- /libs/ItemBonusLib-1.0/Locales/deDE.lua: -------------------------------------------------------------------------------- 1 | if AceLibrary:HasInstance("ItemBonusLib-1.0") then return end 2 | 3 | local L = AceLibrary("AceLocale-2.2"):new("ItemBonusLib") 4 | 5 | L:RegisterTranslations("deDE", function () return { 6 | -- bonus names 7 | NAMES = { 8 | STR = "Stärke", 9 | AGI = "Beweglichkeit", 10 | STA = "Ausdauer", 11 | INT = "Intelligenz", 12 | SPI = "Willenskraft", 13 | ARMOR = "Verstärkte Rüstung", 14 | 15 | ARCANERES = "Arkanwiderstand", 16 | FIRERES = "Feuerwiderstand", 17 | NATURERES = "Naturwiderstand", 18 | FROSTRES = "Frostwiderstand", 19 | SHADOWRES = "Schattenwiderstand", 20 | 21 | FISHING = "Angeln", 22 | MINING = "Bergbau", 23 | HERBALISM = "Kräuterkunde", 24 | SKINNING = "Kürschnerei", 25 | DEFENSE = "Verteidigung", 26 | 27 | BLOCK = "Blockchance", 28 | BLOCKVALUE = "Blockwert", 29 | DODGE = "Ausweichen", 30 | PARRY = "Parieren", 31 | ATTACKPOWER = "Angriffskraft", 32 | ATTACKPOWERUNDEAD = "Angriffskraft gegen Untote", 33 | ATTACKPOWERFERAL = "Angriffskraft in Tierform", 34 | CRIT = "krit. Treffer", 35 | RANGEDATTACKPOWER = "Distanzangriffskraft", 36 | RANGEDCRIT = "krit. Schuss", 37 | TOHIT = "Trefferchance", 38 | DMG = "Zauberschaden", 39 | DMGUNDEAD = "Zauberschaden gegen Untote", 40 | ARCANEDMG = "Arkanschaden", 41 | FIREDMG = "Feuerschaden", 42 | FROSTDMG = "Frostschaden", 43 | HOLYDMG = "Heiligschaden", 44 | NATUREDMG = "Naturschaden", 45 | SHADOWDMG = "Schattenschaden", 46 | HOLYCRIT = "krit. Heiligzauber", 47 | SPELLCRIT = "krit. Zauber", 48 | SPELLTOHIT = "Zaubertrefferchance", 49 | SPELLPEN = "Magiedurchdringung", 50 | HEAL = "Heilung", 51 | HEALTHREG = "Lebensregeneration", 52 | MANAREG = "Manaregeneration", 53 | HEALTH = "Lebenspunkte", 54 | MANA = "Manapunkte", 55 | }, 56 | 57 | PATTERNS_PASSIVE = { 58 | { pattern = "%+(%d+) bei allen Widerstandsarten%.", effect = { "ARCANERES", "FIRERES", "FROSTRES", "NATURERES", "SHADOWRES"} }, 59 | { pattern = "Erhöht Eure Chance, Angriffe mit einem Schild zu blocken, um (%d+)%%%.", effect = "BLOCK" }, 60 | { pattern = "Erhöht den Blockwert Eures Schilde?s um (%d+)%.", effect = "BLOCKVALUE" }, 61 | { pattern = "Erhöht Eure Chance, einem Angriff auszuweichen, um (%d+)%%%.", effect = "DODGE" }, 62 | { pattern = "Erhöht Eure Chance, einen Angriff zu parieren, um (%d+)%%%.", effect = "PARRY" }, 63 | { pattern = "Erhöht Eure Chance, einen kritischen Treffer durch Zauber zu erzielen, um (%d+)%%%.", effect = "SPELLCRIT" }, 64 | { pattern = "Erhöht Eure Chance, einen kritischen Treffer durch Heiligzauber zu erzielen, um (%d+)%%%.", effect = "HOLYCRIT" }, 65 | { pattern = "Erhöht Eure Chance, einen kritischen Treffer zu erzielen, um (%d+)%%%.", effect = "CRIT" }, 66 | { pattern = "Erhöht Eure Chance, mit Geschosswaffen einen kritischen Schlag zu erzielen, um (%d+)%.", effect = "RANGEDCRIT" }, 67 | { pattern = "Erhöht durch Arkanzauber und Arkaneffekte zugefügten Schaden um bis zu (%d+)%.", effect = "ARCANEDMG" }, 68 | { pattern = "Erhöht durch Feuerzauber und Feuereffekte zugefügten Schaden um bis zu (%d+)%.", effect = "FIREDMG" }, 69 | { pattern = "Erhöht durch Frostzauber und Frosteffekte zugefügten Schaden um bis zu (%d+)%.", effect = "FROSTDMG" }, 70 | { pattern = "Erhöht durch Heiligzauber und Heiligeffekte zugefügten Schaden um bis zu (%d+)%.", effect = "HOLYDMG" }, 71 | { pattern = "Erhöht durch Naturzauber und Natureffekte zugefügten Schaden um bis zu (%d+)%.", effect = "NATUREDMG" }, 72 | { pattern = "Erhöht durch Schattenzauber und Schatteneffekte zugefügten Schaden um bis zu (%d+)%.", effect = "SHADOWDMG" }, 73 | { pattern = "Erhöht durch Zauber und magische Effekte zugefügten Schaden und Heilung um bis zu (%d+)%.", effect = {"HEAL","DMG"} }, 74 | { pattern = "Erhöht den durch magische Zauber und magische Effekte zugefügten Schaden gegen Untote um bis zu (%d+)", effect = "DMGUNDEAD" }, 75 | { pattern = "+(%d+) Angriffskraft gegen Untote.", effect = "ATTACKPOWERUNDEAD" }, 76 | { pattern = "Erhöht durch Zauber und Effekte verursachte Heilung um bis zu (%d+)%.", effect = "HEAL" }, 77 | { pattern = "Erhöht die durch Zauber und Effekte verursachte Heilung um bis zu (%d+)%.", effect = "HEAL" }, 78 | { pattern = "Stellt alle 5 Sek%. (%d+) Punkt%(e%) Gesundheit wieder her%.", effect = "HEALTHREG" }, 79 | { pattern = "Stellt alle 5 Sek%. (%d+) Punkt%(e%) Mana wieder her%.", effect = "MANAREG" }, 80 | { pattern = "Verbessert Eure Trefferchance um (%d+)%%%.", effect = "TOHIT" }, 81 | { pattern = "Erhöht Eure Chance mit Zaubern zu treffen um (%d+)%%%.", effect = "SPELLTOHIT" }, 82 | { pattern = "Reduziert die Magiewiderstände der Ziele Eurer Zauber um (%d+)%.", effect = "SPELLPEN" } 83 | }, 84 | 85 | 86 | PATTERNS_GENERIC_LOOKUP = { 87 | ["Alle Werte"] = {"STR", "AGI", "STA", "INT", "SPI"}, 88 | ["Stärke"] = "STR", 89 | ["Beweglichkeit"] = "AGI", 90 | ["Ausdauer"] = "STA", 91 | ["Intelligenz"] = "INT", 92 | ["Willenskraft"] = "SPI", 93 | 94 | ["Alle Widerstandsarten"] = { "ARCANERES", "FIRERES", "FROSTRES", "NATURERES", "SHADOWRES"}, 95 | 96 | ["Angeln"] = "FISHING", 97 | ["Angelköder"] = "FISHING", 98 | ["Bergbau"] = "MINING", 99 | ["Kräuterkunde"] = "HERBALISM", 100 | ["Kürschnerei"] = "SKINNING", 101 | ["Verteidigung"] = "DEFENSE", 102 | ["Verteidigungsfertigkeit"] = "DEFENSE", 103 | 104 | ["Angriffskraft"] = "ATTACKPOWER", 105 | ["Angriffskraft gegen Untote"] = "ATTACKPOWERUNDEAD", 106 | ["Angriffskraft in Katzengestalt, Bärengestalt oder Terrorbärengestalt"] = "ATTACKPOWERFERAL", 107 | ["Ausweichen"] = "DODGE", 108 | ["Blocken"] = "BLOCK", 109 | ["Blockwert"] = "BLOCKVALUE", 110 | ["Trefferchance"] = "TOHIT", 111 | ["Distanzangriffskraft"] = "RANGEDATTACKPOWER", 112 | ["Gesundheit alle 5 Sek"] = "HEALTHREG", 113 | ["Heilzauber"] = "HEAL", 114 | ["Mana alle 5 Sek"] = "MANAREG", 115 | ["Manaregeneration"] = "MANAREG", 116 | ["Zauberschaden erhöhen"]= "DMG", 117 | ["Kritischer Treffer"] = "CRIT", 118 | ["Zauberschaden"] = {"HEAL","DMG"}, 119 | ["Blocken"] = "BLOCK", 120 | ["Gesundheit"] = "HEALTH", 121 | ["HP"] = "HEALTH", 122 | ["Heilzauber"] = "HEAL", 123 | ["Heilung und Zauberschaden"] = {"HEAL","DMG"}, 124 | ["Zauberschaden und Heilung"] = {"HEAL","DMG"}, 125 | ["Schadenszauber und Heilzauber"] = {"HEAL","DMG"}, 126 | ["Schadens- und Heilzauber"] = {"HEAL","DMG"}, 127 | ["Zaubertrefferchance"] = "SPELLTOHIT", 128 | 129 | ["Mana"] = "MANA", 130 | ["Rüstung"] = "ARMOR", 131 | ["Verstärkte Rüstung"]= "ARMOR" 132 | }, 133 | 134 | PATTERNS_GENERIC_STAGE1 = { 135 | { pattern = "Arkan", effect = "ARCANE" }, 136 | { pattern = "Feuer", effect = "FIRE" }, 137 | { pattern = "Frost", effect = "FROST" }, 138 | { pattern = "Heilig", effect = "HOLY" }, 139 | { pattern = "Schatten", effect = "SHADOW" }, 140 | { pattern = "Natur", effect = "NATURE" }, 141 | }, 142 | 143 | PATTERNS_GENERIC_STAGE2 = { 144 | { pattern = "widerst", effect = "RES" }, 145 | { pattern = "schaden", effect = "DMG" }, 146 | { pattern = "effekte", effect = "DMG" }, 147 | }, 148 | 149 | 150 | PATTERNS_OTHER = { 151 | { pattern = "Manaregeneration (%d+) per 5 Sek%.", effect = "MANAREG" }, 152 | 153 | { pattern = "Schwaches Zauberöl", effect = {"DMG", "HEAL"}, value = 8 }, 154 | { pattern = "Geringes Zauberöl", effect = {"DMG", "HEAL"}, value = 16 }, 155 | { pattern = "Zauberöl", effect = {"DMG", "HEAL"}, value = 24 }, 156 | { pattern = "Hervorragendes Zauberöl", effect = {"DMG", "HEAL", "SPELLCRIT"}, value = {36, 36, 1} }, 157 | 158 | { pattern = "Schwaches Manaöl", effect = "MANAREG", value = 4 }, 159 | { pattern = "Geringes Manaöl", effect = "MANAREG", value = 8 }, 160 | { pattern = "Hervorragendes Manaöl", effect = { "MANAREG", "HEAL"}, value = {12, 25} }, 161 | 162 | { pattern = "Eterniumschnur", effect = "FISHING", value = 5 }, 163 | 164 | { pattern = "Heilung %+31 und 5 Mana alle 5 Sek%.", effect = { "MANAREG", "HEAL"}, value = {5, 31} }, 165 | { pattern = "Ausdauer %+16 und Rüstung %+100", effect = { "STA", "ARMOR"}, value = {16, 100} }, 166 | { pattern = "Angriffskraft %+26 und %+1%% kritische Treffer", effect = { "ATTACKPOWER", "CRIT"}, value = {26, 1} }, 167 | { pattern = "Zauberschaden %+15 und %+1%% kritische Zaubertreffer", effect = { "DMG", "HEAL", "SPELLCRIT"}, value = {15, 15, 1} }, 168 | } 169 | } end) 170 | -------------------------------------------------------------------------------- /libs/ItemBonusLib-1.0/Locales/enUS.lua: -------------------------------------------------------------------------------- 1 | if AceLibrary:HasInstance("ItemBonusLib-1.0") then return end 2 | 3 | local L = AceLibrary("AceLocale-2.2"):new("ItemBonusLib") 4 | 5 | L:RegisterTranslations("enUS", function () return { 6 | CHAT_COMMANDS = { "/abonus" }, 7 | ["An addon to get information about bonus from equipped items"] = true, 8 | ["show"] = true, 9 | ["Show all bonuses from the current equipment"] = true, 10 | ["Current equipment bonuses:"] = true, 11 | ["details"] = true, 12 | ["Shows bonuses with slot distribution"] = true, 13 | ["Current equipment bonus details:"] = true, 14 | ["item"] = true, 15 | ["show bonuses of given itemlink"] = true, 16 | [""] = true, 17 | ["Bonuses for %s:"] = true, 18 | ["Item is part of set [%s]"] = true, 19 | [" %sBonus for %d pieces :"] = true, 20 | ["slot"] = true, 21 | ["show bonuses of given slot"] = true, 22 | [""] = true, 23 | ["Bonuses of slot %s:"] = true, 24 | 25 | -- bonus names 26 | NAMES = { 27 | STR = "Strength", 28 | AGI = "Agility", 29 | STA = "Stamina", 30 | INT = "Intellect", 31 | SPI = "Spirit", 32 | ARMOR = "Reinforced Armor", 33 | 34 | ARCANERES = "Arcane Resistance", 35 | FIRERES = "Fire Resistance", 36 | NATURERES = "Nature Resistance", 37 | FROSTRES = "Frost Resistance", 38 | SHADOWRES = "Shadow Resistance", 39 | 40 | FISHING = "Fishing", 41 | MINING = "Mining", 42 | HERBALISM = "Herbalism", 43 | SKINNING = "Skinning", 44 | DEFENSE = "Defense", 45 | 46 | BLOCK = "Chance to Block", 47 | BLOCKVALUE = "Block value", 48 | DODGE = "Dodge", 49 | PARRY = "Parry", 50 | ATTACKPOWER = "Attack Power", 51 | ATTACKPOWERUNDEAD = "Attack Power against Undead", 52 | ATTACKPOWERFERAL = "Attack Power in feral form", 53 | CRIT = "Crit. hits", 54 | RANGEDATTACKPOWER = "Ranged Attack Power", 55 | RANGEDCRIT = "Crit. Shots", 56 | TOHIT = "Chance to Hit", 57 | 58 | DMG = "Spell Damage", 59 | DMGUNDEAD = "Spell Damage against Undead", 60 | ARCANEDMG = "Arcane Damage", 61 | FIREDMG = "Fire Damage", 62 | FROSTDMG = "Frost Damage", 63 | HOLYDMG = "Holy Damage", 64 | NATUREDMG = "Nature Damage", 65 | SHADOWDMG = "Shadow Damage", 66 | SPELLCRIT = "Crit. Spell", 67 | SPELLTOHIT = "Chance to Hit with spells", 68 | SPELLPEN = "Spell Penetration", 69 | HEAL = "Healing", 70 | HOLYCRIT = "Crit. Holy Spell", 71 | 72 | HEALTHREG = "Life Regeneration", 73 | MANAREG = "Mana Regeneration", 74 | HEALTH = "Life Points", 75 | MANA = "Mana Points" 76 | }; 77 | 78 | 79 | -- passive bonus patterns. checked against lines which start with above prefixes 80 | PATTERNS_PASSIVE = { 81 | { pattern = "+(%d+) ranged Attack Power%.", effect = "RANGEDATTACKPOWER" }, 82 | { pattern = "Increases your chance to block attacks with a shield by (%d+)%%%.", effect = "BLOCK" }, 83 | { pattern = "Increases the block value of your shield by (%d+)%.", effect = "BLOCKVALUE" }, 84 | { pattern = "Increases your chance to dodge an attack by (%d+)%%%.", effect = "DODGE" }, 85 | { pattern = "Increases your chance to parry an attack by (%d+)%%%.", effect = "PARRY" }, 86 | { pattern = "Improves your chance to get a critical strike with spells by (%d+)%%%.", effect = "SPELLCRIT" }, 87 | { pattern = "Improves your chance to get a critical strike with Holy spells by (%d+)%%%.", effect = "HOLYCRIT" }, 88 | { pattern = "Increases the critical effect chance of your Holy spells by (%d+)%%%.", effect = "HOLYCRIT" }, 89 | { pattern = "Improves your chance to get a critical strike by (%d+)%%%.", effect = "CRIT" }, 90 | { pattern = "Improves your chance to get a critical strike with missile weapons by (%d+)%%%.", effect = "RANGEDCRIT" }, 91 | { pattern = "Increases damage done by Arcane spells and effects by up to (%d+)%.", effect = "ARCANEDMG" }, 92 | { pattern = "Increases damage done by Fire spells and effects by up to (%d+)%.", effect = "FIREDMG" }, 93 | { pattern = "Increases damage done by Frost spells and effects by up to (%d+)%.", effect = "FROSTDMG" }, 94 | { pattern = "Increases damage done by Holy spells and effects by up to (%d+)%.", effect = "HOLYDMG" }, 95 | { pattern = "Increases damage done by Nature spells and effects by up to (%d+)%.", effect = "NATUREDMG" }, 96 | { pattern = "Increases damage done by Shadow spells and effects by up to (%d+)%.", effect = "SHADOWDMG" }, 97 | { pattern = "Increases healing done by spells and effects by up to (%d+)%.", effect = "HEAL" }, 98 | { pattern = "Increases damage and healing done by magical spells and effects by up to (%d+)%.", effect = {"HEAL", "DMG"} }, 99 | { pattern = "Increases damage done to Undead by magical spells and effects by up to (%d+)", effect = "DMGUNDEAD" }, 100 | { pattern = "+(%d+) Attack Power when fighting Undead.", effect = "ATTACKPOWERUNDEAD" }, 101 | { pattern = "Restores (%d+) health per 5 sec%.", effect = "HEALTHREG" }, 102 | { pattern = "Restores (%d+) health every 5 sec%.", effect = "HEALTHREG" }, -- both versions ('per' and 'every') seem to be used 103 | { pattern = "Restores (%d+) mana per 5 sec%.", effect = "MANAREG" }, 104 | { pattern = "Restores (%d+) mana every 5 sec%.", effect = "MANAREG" }, 105 | { pattern = "Improves your chance to hit by (%d+)%%%.", effect = "TOHIT" }, 106 | { pattern = "Improves your chance to hit with spells by (%d+)%%%.", effect = "SPELLTOHIT" }, 107 | { pattern = "Decreases the magical resistances of your spell targets by (%d+).", effect = "SPELLPEN" }, 108 | 109 | -- Added for HealPoints 110 | { pattern = "Allows (%d+)%% of your Mana regeneration to continue while casting%.", effect = "CASTINGREG"}, 111 | { pattern = "Improves your chance to get a critical strike with Nature spells by (%d+)%%%.", effect = "NATURECRIT"}, 112 | { pattern = "Reduces the casting time of your Regrowth spell by 0%.(%d+) sec%.", effect = "CASTINGREGROWTH"}, 113 | { pattern = "Reduces the casting time of your Holy Light spell by 0%.(%d+) sec%.", effect = "CASTINGHOLYLIGHT"}, 114 | { pattern = "Reduces the casting time of your Healing Touch spell by 0%.(%d+) sec%.", effect = "CASTINGHEALINGTOUCH"}, 115 | { pattern = "%-0%.(%d+) sec to the casting time of your Flash Heal spell%.", effect = "CASTINGFLASHHEAL"}, 116 | { pattern = "%-0%.(%d+) seconds on the casting time of your Chain Heal spell%.", effect = "CASTINGCHAINHEAL"}, 117 | { pattern = "Increases the duration of your Rejuvenation spell by (%d+) sec%.", effect = "DURATIONREJUV"}, 118 | { pattern = "Increases the duration of your Renew spell by (%d+) sec%.", effect = "DURATIONRENEW"}, 119 | { pattern = "Increases your normal health and mana regeneration by (%d+)%.", effect = "MANAREGNORMAL"}, 120 | { pattern = "Increases the amount healed by Chain Heal to targets beyond the first by (%d+)%%%.", effect = "IMPCHAINHEAL"}, 121 | { pattern = "Increases healing done by Rejuvenation by up to (%d+)%.", effect = "IMPREJUVENATION"}, 122 | { pattern = "Increases healing done by Lesser Healing Wave by up to (%d+)%.", effect = "IMPLESSERHEALINGWAVE"}, 123 | { pattern = "Increases healing done by Flash of Light by up to (%d+)%.", effect = "IMPFLASHOFLIGHT"}, 124 | { pattern = "After casting your Healing Wave or Lesser Healing Wave spell%, gives you a 25%% chance to gain Mana equal to (%d+)%% of the base cost of the spell%.", effect = "REFUNDHEALINGWAVE"}, 125 | { pattern = "Your Healing Wave will now jump to additional nearby targets%. Each jump reduces the effectiveness of the heal by (%d+)%%%, and the spell will jump to up to two additional targets%.", effect = "JUMPHEALINGWAVE"}, 126 | { pattern = "Reduces the mana cost of your Healing Touch%, Regrowth%, Rejuvenation and Tranquility spells by (%d+)%%%.", effect = "CHEAPERDRUID"}, 127 | { pattern = "On Healing Touch critical hits%, you regain (%d+)%% of the mana cost of the spell%.", effect = "REFUNDHTCRIT"}, 128 | { pattern = "Reduces the mana cost of your Renew spell by (%d+)%%%.", effect = "CHEAPERRENEW"}, 129 | }; 130 | 131 | -- generic patterns have the form "+xx bonus" or "bonus +xx" with an optional % sign after the value. 132 | 133 | -- first the generic bonus string is looked up in the following table 134 | PATTERNS_GENERIC_LOOKUP = { 135 | ["All Stats"] = {"STR", "AGI", "STA", "INT", "SPI"}, 136 | ["Strength"] = "STR", 137 | ["Agility"] = "AGI", 138 | ["Stamina"] = "STA", 139 | ["Intellect"] = "INT", 140 | ["Spirit"] = "SPI", 141 | 142 | ["All Resistances"] = { "ARCANERES", "FIRERES", "FROSTRES", "NATURERES", "SHADOWRES"}, 143 | 144 | ["Fishing"] = "FISHING", 145 | ["Fishing Lure"] = "FISHING", 146 | ["Increased Fishing"] = "FISHING", 147 | ["Mining"] = "MINING", 148 | ["Herbalism"] = "HERBALISM", 149 | ["Skinning"] = "SKINNING", 150 | ["Defense"] = "DEFENSE", 151 | ["Increased Defense"] = "DEFENSE", 152 | 153 | ["Attack Power"] = "ATTACKPOWER", 154 | ["Attack Power when fighting Undead"] = "ATTACKPOWERUNDEAD", 155 | ["Attack Power in Cat, Bear, and Dire Bear forms only"] = "ATTACKPOWERFERAL", 156 | 157 | ["Dodge"] = "DODGE", 158 | ["Block"] = "BLOCK", 159 | ["Block Value"] = "BLOCKVALUE", 160 | ["Hit"] = "TOHIT", 161 | ["Spell Hit"] = "SPELLTOHIT", 162 | ["Blocking"] = "BLOCK", 163 | ["Ranged Attack Power"] = "RANGEDATTACKPOWER", 164 | ["health every 5 sec"] = "HEALTHREG", 165 | ["Healing Spells"] = "HEAL", 166 | ["Increases Healing"] = "HEAL", 167 | ["Healing and Spell Damage"] = {"HEAL", "DMG"}, 168 | ["Damage and Healing Spells"] = {"HEAL", "DMG"}, 169 | ["Spell Damage and Healing"] = {"HEAL", "DMG"}, 170 | ["mana every 5 sec"] = "MANAREG", 171 | ["Mana Regen"] = "MANAREG", 172 | ["Spell Damage"] = {"HEAL", "DMG"}, 173 | ["Critical"] = "CRIT", 174 | ["Critical Hit"] = "CRIT", 175 | ["Damage"] = "DMG", 176 | ["Health"] = "HEALTH", 177 | ["HP"] = "HEALTH", 178 | ["Mana"] = "MANA", 179 | ["Armor"] = "ARMOR", 180 | ["Reinforced Armor"] = "ARMOR", 181 | }; 182 | 183 | -- next we try to match against one pattern of stage 1 and one pattern of stage 2 and concatenate the effect strings 184 | PATTERNS_GENERIC_STAGE1 = { 185 | { pattern = "Arcane", effect = "ARCANE" }, 186 | { pattern = "Fire", effect = "FIRE" }, 187 | { pattern = "Frost", effect = "FROST" }, 188 | { pattern = "Holy", effect = "HOLY" }, 189 | { pattern = "Shadow", effect = "SHADOW" }, 190 | { pattern = "Nature", effect = "NATURE" } 191 | }; 192 | 193 | PATTERNS_GENERIC_STAGE2 = { 194 | { pattern = "Resist", effect = "RES" }, 195 | { pattern = "Damage", effect = "DMG" }, 196 | { pattern = "Effects", effect = "DMG" }, 197 | }; 198 | 199 | -- finally if we got no match, we match against some special enchantment patterns. 200 | PATTERNS_OTHER = { 201 | { pattern = "Mana Regen (%d+) per 5 sec%.", effect = "MANAREG" }, 202 | 203 | { pattern = "Minor Wizard Oil", effect = {"DMG", "HEAL"}, value = 8 }, 204 | { pattern = "Lesser Wizard Oil", effect = {"DMG", "HEAL"}, value = 16 }, 205 | { pattern = "Wizard Oil", effect = {"DMG", "HEAL"}, value = 24 }, 206 | { pattern = "Brilliant Wizard Oil", effect = {"DMG", "HEAL", "SPELLCRIT"}, value = {36, 36, 1} }, 207 | 208 | { pattern = "Minor Mana Oil", effect = "MANAREG", value = 4 }, 209 | { pattern = "Lesser Mana Oil", effect = "MANAREG", value = 8 }, 210 | { pattern = "Brilliant Mana Oil", effect = { "MANAREG", "HEAL"}, value = {12, 25} }, 211 | 212 | { pattern = "Eternium Line", effect = "FISHING", value = 5 }, 213 | 214 | { pattern = "Healing %+31 and 5 mana per 5 sec%.", effect = { "MANAREG", "HEAL"}, value = {5, 31} }, 215 | { pattern = "Stamina %+16 and Armor %+100", effect = { "STA", "ARMOR"}, value = {16, 100} }, 216 | { pattern = "Attack Power %+26 and %+1%% Critical Strike", effect = { "ATTACKPOWER", "CRIT"}, value = {26, 1} }, 217 | { pattern = "Spell Damage %+15 and %+1%% Spell Critical Strike", effect = { "DMG", "HEAL", "SPELLCRIT"}, value = {15, 15, 1} }, 218 | 219 | } 220 | } end) 221 | -------------------------------------------------------------------------------- /libs/ItemBonusLib-1.0/Locales/frFR.lua: -------------------------------------------------------------------------------- 1 | if AceLibrary:HasInstance("ItemBonusLib-1.0") then return end 2 | 3 | local L = AceLibrary("AceLocale-2.2"):new("ItemBonusLib") 4 | 5 | L:RegisterTranslations("frFR", function () return { 6 | -- bonus names 7 | NAMES = { 8 | STR = "Force", 9 | AGI = "Agilité", 10 | STA = "Endurance", 11 | INT = "Intelligence", 12 | SPI = "Esprit", 13 | ARMOR = "Bonus d'Armure", 14 | 15 | ARCANERES = "Arcane", 16 | FIRERES = "Feu", 17 | NATURERES = "Nature", 18 | FROSTRES = "Givre", 19 | SHADOWRES = "Ombre", 20 | 21 | FISHING = "Pêche", 22 | MINING = "Minage", 23 | HERBALISM = "Herborisme", 24 | SKINNING = "Dépeçage", 25 | DEFENSE = "Défense", 26 | 27 | BLOCK = "Chance de Bloquer", 28 | BLOCKVALUE = "Valeur de blocage", 29 | DODGE = "Esquive", 30 | PARRY = "Parade", 31 | ATTACKPOWER = "Puissance d'attaque", 32 | ATTACKPOWERUNDEAD = "Puissance d'attaque contre les morts-vivants", 33 | ATTACKPOWERFERAL = "Puissance d'attaque en forme férale", 34 | CRIT = "Coups Critiques", 35 | RANGEDATTACKPOWER = "Puissance d'attaque à distance", 36 | RANGEDCRIT = "Tirs Crit.", 37 | TOHIT = "Chances de toucher", 38 | 39 | DMG = "Dégâts", 40 | DMGUNDEAD = "Dégâts des sorts contre les morts-vivants", 41 | ARCANEDMG = "Dégâts d'Arcanes", 42 | FIREDMG = "Dégâts de Feu", 43 | FROSTDMG = "Dégâts de Froid", 44 | HOLYDMG = "Dégâts Sacrés", 45 | NATUREDMG = "Dégâts de Nature", 46 | SHADOWDMG = "Dégâts des Ombres", 47 | SPELLCRIT = "Critiques", 48 | HEAL = "Soins", 49 | HOLYCRIT = "Soins Crit.", 50 | SPELLTOHIT = "Chance de toucher avec les sorts", 51 | SPELLPEN = "Diminue les résistances", 52 | 53 | HEALTHREG = "Régeneration Vie", 54 | MANAREG = "Régeneration Mana", 55 | HEALTH = "Points de Vie", 56 | MANA = "Points de Mana", 57 | }, 58 | 59 | PATTERNS_PASSIVE = { 60 | { pattern = "+(%d+) à la puissance d'attaque%.", effect = "ATTACKPOWER" }, 61 | { pattern = "+(%d+) à la puissance d'attaque lorsque vous combattez des morts%-vivants%.", effect = "ATTACKPOWERUNDEAD" }, 62 | { pattern = "+(%d+) à la puissance des attaques à distance%.", effect = "RANGEDATTACKPOWER" }, 63 | { pattern = "Augmente vos chances de bloquer les attaques avec un bouclier de (%d+)%%%.", effect = "BLOCK" }, 64 | { pattern = "Augmente le score de blocage de votre bouclier de (%d+)%.", effect = "BLOCKVALUE" }, 65 | { pattern = "Augmente vos chances d'esquiver une attaque de (%d+)%%%.", effect = "DODGE" }, 66 | { pattern = "Augmente vos chances de parer une attaque de (%d+)%%%.", effect = "PARRY" }, 67 | { pattern = "Augmente vos chances d'infliger un coup critique avec vos sorts de (%d+)%%%.", effect = "SPELLCRIT" }, 68 | { pattern = "Augmente vos chances d'infliger un coup critique de (%d+)%%%.", effect = "CRIT" }, 69 | { pattern = "Augmente vos chances d'infliger un coup critique avec une arme à feu par (%d+)%%%.", effect = "RANGEDCRIT" }, 70 | { pattern = "Augmente vos chances de lancer un soin critique par (%d+)%%%.", effect = "HEALCRIT" }, 71 | { pattern = "Augmente les dégâts infligés par les effets et les sorts des Arcanes de (%d+)% au maximum%.", effect = "ARCANEDMG" }, 72 | { pattern = "Augmente les dégâts infligés par les sorts et effets de Feu de (%d+)% au maximum%.", effect = "FIREDMG" }, 73 | { pattern = "Augmente les dégâts infligés par les sorts et les effets de givre de (%d+)% au maximum%.", effect = "FROSTDMG" }, 74 | { pattern = "Augmente les dommages realises par les sorts Sacrés de (%d+)%.", effect = "HOLYDMG" }, 75 | { pattern = "Augmente les dégâts infligés par les sorts et les effets de Nature (%d+)% au maximum%.", effect = "NATUREDMG" }, 76 | { pattern = "Augmente les dégâts infligés par les sorts et les effets d'ombre de (%d+)% au maximum%.", effect = "SHADOWDMG" }, 77 | { pattern = "(%d+)% aux dégâts des sorts d'ombres%.", effect = "SHADOWDMG" }, 78 | { pattern = "Augmente les effets des sorts de soins de (%d+)% au maximum%.", effect = "HEAL" }, 79 | { pattern = "Augmente les soins prodigués par les sorts et effets de (%d+)% au maximum%.", effect = "HEAL"}, 80 | { pattern = "Augmente les soins et dégâts produits par les sorts et effets magiques de (%d+) au maximum%.", effect = {"HEAL", "DMG" }}, 81 | { pattern = "Augmente les dégâts et les soins produits par les sorts et effets magiques de (%d+) au maximum%.", effect = {"HEAL", "DMG" }}, 82 | { pattern = "Augmente les dégâts infligés aux morts%-vivants par les sorts et effets magiques d'un maximum de (%d+)%.", effect = "DMGUNDEAD" }, 83 | { pattern = "Rend (%d+) points de vie toutes les 5 sec%.", effect = "HEALTHREG" }, 84 | { pattern = "Rend (%d+) points de mana toutes les 5 secondes%.", effect = "MANAREG" }, 85 | { pattern = "Augmente vos chances de toucher de (%d+)%%%.", effect = "TOHIT" }, 86 | { pattern = "Augmente vos chances de toucher avec des sorts de (%d+)%%%.", effect = "SPELLTOHIT" }, 87 | { pattern = "Diminue les résistances magiques des cibles de vos sorts de (%d+)%.", effect = "SPELLPEN" }, 88 | { pattern = "Pêche augmentée de (%d+).", effect = "FISHING" }, 89 | { pattern = "Défense augmentée de (%d+).", effect = "DEFENSE"}, 90 | { pattern = "+(%d+) à l'Armure", effect = "ARMOR"}, 91 | { pattern = "+(%d+) à la puissance d'attaque pour les formes de félin, d'ours et d'ours redoutable uniquement%.", effect = "ATTACKPOWERFERAL"}, 92 | { pattern = "+(%d+) à toutes les résistances%.", effect = { "ARCANERES", "FIRERES", "FROSTRES", "NATURERES", "SHADOWRES"}}, 93 | 94 | -- Added 95 | { pattern = "(%d+)%% de votre vitesse de récupération du Mana sont actifs lorsque vous incantez%.", effect = "CASTINGREG"}, 96 | { pattern = "Vous confère (%d+)%% de votre vitesse normale de récupération du mana pendant l'incantation%.", effect = "CASTINGREG"}, 97 | { pattern = "Augmente vos chances d'infliger un coup critique avec les sorts de Nature de (%d+)%%%.", effect = "NATURECRIT"}, 98 | { pattern = "Réduit le temps d'incantation de votre sort Rétablissement de 0.(%d+) sec%.", effect = "CASTINGREGROWTH"}, 99 | { pattern = "Réduit le temps d'incantation de votre sort Lumière sacrée de 0.(%d+) sec%.", effect = "CASTINGHOLYLIGHT"}, 100 | { pattern = "-0.(%d+) sec. au temps d'incantation de votre sort Soins rapides%.", effect = "CASTINGFLASHHEAL"}, 101 | { pattern = "-0.(%d+) secondes au temps d'incantation de votre sort Salve de guérison%.", effect = "CASTINGCHAINHEAL"}, 102 | { pattern = "Réduit le temps de lancement de Toucher Guérisseur de 0.(%d+) secondes%.", effect = "CASTINGHEALINGTOUCH"}, 103 | { pattern = "Augmente la durée de votre sort Récupération de (%d+) sec%.", effect = "DURATIONREJUV"}, 104 | { pattern = "Augmente la durée de votre sort Rénovation de (%d+) sec%.", effect = "DURATIONRENEW"}, 105 | { pattern = "Augmente la régénération des points de vie et de mana de (%d+)%.", effect = "MANAREGNORMAL"}, 106 | { pattern = "Augmente de (%d+)%% le montant de points de vie rendus par Salve de guérison aux cibles qui suivent la première%.", effect = "IMPCHAINHEAL"}, 107 | { pattern = "Augmente les soins prodigués par Récupération de (%d+) au maximum%.", effect = "IMPREJUVENATION"}, 108 | { pattern = "Augmente les soins prodigués par votre Vague de Soins Inférieurs de (%d+)%.", effect = "IMPLESSERHEALINGWAVE"}, 109 | { pattern = "Augmente les soins prodigués par votre Eclair lumineux de (%d+)%.", effect = "IMPFLASHOFLIGHT"}, 110 | { pattern = "Après avoir lancé un sort de Vague de soins ou de Vague de soins inférieurs, vous avez 25%% de chances de gagner un nombre de points de mana égal à (%d+)%% du coût de base du sort%.", effect = "REFUNDHEALINGWAVE"}, 111 | { pattern = "Votre Vague de soins soigne aussi des cibles proches supplémentaires. Chaque nouveau soin perd (%d+)%% d'efficacité, et le sort soigne jusqu'à deux cibles supplémentaires%.", effect = "JUMPHEALINGWAVE"}, 112 | { pattern = "Réduit de (%d+)%% le coût en mana de vos sorts Toucher guérisseur% Rétablissement% Récupération et Tranquillité%.", effect = "CHEAPERDRUID"}, 113 | { pattern = "En cas de réussite critique sur un Toucher guérisseur, vous récupérez (%d+)%% du coût en mana du sort%.", effect = "REFUNDHTCRIT"}, 114 | { pattern = "Reduit le coût en mana de votre sort Rénovation de (%d+)%%%.", effect = "CHEAPERRENEW"}, 115 | }, 116 | 117 | 118 | PATTERNS_GENERIC_LOOKUP = { 119 | ["Toutes les caractéristiques"] = {"STR", "AGI", "STA", "INT", "SPI"}, 120 | ["Force"] = "STR", 121 | ["Agilité"] = "AGI", 122 | ["Endurance"] = "STA", 123 | ["Intelligence"] = "INT", 124 | ["Esprit"] = "SPI", 125 | ["à toutes les résistances"] = { "ARCANERES", "FIRERES", "FROSTRES", "NATURERES", "SHADOWRES"}, 126 | ["Pêche"] = "FISHING", 127 | ["Minage"] = "MINING", 128 | ["Herborisme"] = "HERBALISM", 129 | ["Dépeçage"] = "SKINNING", 130 | ["Défense"] = "DEFENSE", 131 | ["puissance d'Attaque"] = "ATTACKPOWER", 132 | ["Puissance d'attaque contre les morts%-vivants"] = "ATTACKPOWERUNDEAD", 133 | ["Esquive"] = "DODGE", 134 | ["Blocage"] = "BLOCK", 135 | ["Score de blocage"] = "BLOCKVALUE", 136 | ["Puissance d'Attaque à distance"] = "RANGEDATTACKPOWER", 137 | ["Soins chaque 5 sec."] = "HEALTHREG", 138 | ["Sorts de Soins"] = "HEAL", 139 | ["Sorts de soin"] = "HEAL", 140 | ["Sorts de soins"] = "HEAL", 141 | ["Mana chaque 5 sec."] = "MANAREG", 142 | ["Sorts de Dommages"] = "DMG", 143 | ["dégâts des sorts"] = {"HEAL", "DMG"}, 144 | ["dégâts et les effets des sorts"] = "DMG", 145 | ["aux dégâts des sorts et aux soins"] = {"HEAL", "DMG"}, 146 | ["points de mana toutes les 5 sec"] = "MANAREG", 147 | ["aux sorts de soins"] = "HEAL", 148 | ["Armure"] = "ARMOR", 149 | ["Armure"] = "ARMOR", 150 | ["Bloquer"] = "BLOCKVALUE", 151 | ["Coup Critique"] = "CRIT", 152 | ["Dommage"] = "DMG", 153 | ["Soins"] = "HEALTH", 154 | ["Mana"] = "MANA", 155 | ["Armure renforcée"] = "ARMOR", 156 | }, 157 | 158 | PATTERNS_GENERIC_STAGE1 = { 159 | { pattern = "Arcane", effect = "ARCANE" }, 160 | { pattern = "Feu", effect = "FIRE" }, 161 | { pattern = "Givre", effect = "FROST" }, 162 | { pattern = "Sacré", effect = "HOLY" }, 163 | { pattern = "Ombre", effect = "SHADOW" }, 164 | { pattern = "Nature", effect = "NATURE" }, 165 | { pattern = "arcanes", effect = "ARCANE" }, 166 | { pattern = "feu", effect = "FIRE" }, 167 | { pattern = "givre", effect = "FROST" }, 168 | { pattern = "ombre", effect = "SHADOW" }, 169 | { pattern = "nature", effect = "NATURE" } 170 | }, 171 | 172 | PATTERNS_GENERIC_STAGE2 = { 173 | { pattern = "résistance", effect = "RES" }, 174 | { pattern = "dégâts", effect = "DMG" }, 175 | { pattern = "effets", effect = "DMG" } 176 | }, 177 | 178 | 179 | PATTERNS_OTHER = { 180 | { pattern = "(%d+) Mana chaque 5 sec.", effect = "MANAREG" }, --? 181 | { pattern = "Récup. mana (%d+)/5 sec.", effect = "MANAREG" }, --? 182 | { pattern = "Cachet de mojo zandalar", effect = "HEAL", value = 18 }, --? 183 | { pattern = "Cachet de sérénité zandalar", effect = "HEAL", value = 33 }, 184 | 185 | { pattern = "Huile de sorcier mineure", effect = "HEAL", value = 8 }, 186 | { pattern = "Huile de sorcier inférieure", effect = "HEAL", value = 16 }, 187 | { pattern = "Huile de sorcier", effect = "HEAL", value = 24 }, 188 | { pattern = "Huile de sorcier brillante", effect = {"HEAL", "SPELLCRIT"}, value = {36, 1} }, 189 | 190 | { pattern = "Huile de mana mineure", effect = "MANAREG", value = 4 }, 191 | { pattern = "Huile de mana inférieure", effect = "MANAREG", value = 8 }, 192 | { pattern = "Huile de mana brillante", effect = { "MANAREG", "HEAL"}, value = {12, 25} }, 193 | -- enchantements de Saphirron 194 | -- { pattern = "Healing %+31 and 5 mana per 5 sec%.", effect = { "MANAREG", "HEAL"}, value = {5, 31} }, 195 | -- { pattern = "Stamina %+16 and Armor %+100", effect = { "STA", "ARMOR"}, value = {16, 100} }, 196 | -- { pattern = "Attack Power %+26 and %+1%% Critical Strike", effect = { "ATTACKPOWER", "CRIT"}, value = {26, 1} }, 197 | -- { pattern = "Spell Damage %+15 and %+1%% Spell Critical Strike", effect = { "DMG", "HEAL", "SPELLCRIT"}, value = {15, 15, 1} }, 198 | } 199 | } end) 200 | -------------------------------------------------------------------------------- /libs/ItemBonusLib-1.0/Locales/ruRU.lua: -------------------------------------------------------------------------------- 1 | if AceLibrary:HasInstance("ItemBonusLib-1.0") then return end 2 | 3 | local L = AceLibrary("AceLocale-2.2"):new("ItemBonusLib") 4 | 5 | L:RegisterTranslations("ruRU", function () return { 6 | CHAT_COMMANDS = { "/abonus" }, 7 | ["An addon to get information about bonus from equipped items"] = "Этот аддон получает информацию о бонусе от предметов экипировки", 8 | ["Show all bonuses from the current equipment"] = "Показать все бонусы от текущей экипировки", 9 | ["Current equipment bonuses:"] = "Бонусы текущих предметов:", 10 | ["Shows bonuses with slot distribution"] = "Показать бонусы с распределением ячеек", 11 | ["Current equipment bonus details:"] = "Информация о бонусе текущей экипировки:", 12 | ["show bonuses of given itemlink"] = "показать бонусы данной ссылки на предмет", 13 | [""] = "<ссылка на предмет>", 14 | ["Bonuses for %s:"] = "Бонусы для %s:", 15 | ["Item is part of set [%s]"] = "Предмет является частью комплекта [%s]", 16 | [" %sBonus for %d pieces :"] = " %sБонус для %d частей:", 17 | ["show bonuses of given slot"] = "показать бонусы данной ячейки", 18 | [""] = "<название ячейки>", 19 | ["Bonuses of slot %s:"] = "Бонусы ячейки %s:", 20 | 21 | -- bonus names 22 | NAMES = { 23 | STR = "Сила", 24 | AGI = "Ловкость", 25 | STA = "Выносливость", 26 | INT = "Интеллект", 27 | SPI = "Дух", 28 | ARMOR = "Усиленная броня", 29 | 30 | ARCANERES = "Сопротивление тайной магии", 31 | FIRERES = "Сопротивление огню", 32 | NATURERES = "Сопротивление силам природы", 33 | FROSTRES = "Сопротивление магии льда", 34 | SHADOWRES = "Сопротивление темной магии", 35 | 36 | FISHING = "Рыбная ловля", 37 | MINING = "Горное дело", 38 | HERBALISM = "Травничество", 39 | SKINNING = "Снятие шкур", 40 | DEFENSE = "Защита", 41 | 42 | BLOCK = "Вероятность блокирования", 43 | BLOCKVALUE = "Показатель блокирования", 44 | DODGE = "Уклон", 45 | PARRY = "Парир", 46 | ATTACKPOWER = "Сила атаки", 47 | ATTACKPOWERUNDEAD = "Сила атаки против нежити", 48 | ATTACKPOWERFERAL = "Сила атаки в форме животного", 49 | CRIT = "Крит. попадания", 50 | RANGEDATTACKPOWER = "Сила атаки дальнего боя", 51 | RANGEDCRIT = "Крит. выстрелы", 52 | TOHIT = "Шанс попадания", 53 | 54 | DMG = "Урон от заклинания", 55 | DMGUNDEAD = "Урон от заклинаний против нежити", 56 | ARCANEDMG = "Урон от тайной магии", 57 | FIREDMG = "Урон от магии огня", 58 | FROSTDMG = "Урон от магии льда", 59 | HOLYDMG = "Урон от магии Света", 60 | NATUREDMG = "Урон от природы", 61 | SHADOWDMG = "Урон от темной магии", 62 | SPELLCRIT = "Критическое заклинание", 63 | SPELLTOHIT = "Шанс попадания заклинанием", 64 | SPELLPEN = "Проникновение заклинания", 65 | HEAL = "Исцеление", 66 | HOLYCRIT = "Крит. светом", 67 | 68 | HEALTHREG = "Восстановление здоровья", 69 | MANAREG = "Восстановление маны", 70 | HEALTH = "Очки здоровья", 71 | MANA = "Очки маны" 72 | }; 73 | 74 | 75 | -- passive bonus patterns. checked against lines which start with above prefixes 76 | PATTERNS_PASSIVE = { 77 | {pattern = "Увеличивает силу атаки дальнего боя на (%d+)%.", effect = "RANGEDATTACKPOWER"}, 78 | {pattern = "Повышает вероятность блокировать атаку щитом на (%d+)%%%.", effect = "BLOCK"}, 79 | {pattern = "Увеличивает показатель блокирования вашего щита на (%d+) ед%.", effect = "BLOCKVALUE"}, 80 | {pattern = "Повышает вероятность уклонения от атак на (%d+)%%%.", effect = "DODGE"}, 81 | {pattern = "Увеличивает вероятность парирования атак на (%d+)%%%.", effect = "PARRY"}, 82 | {pattern = "Повышает вероятность нанести критический удар заклинаниями на (%d+)%%%.", effect = "SPELLCRIT"}, 83 | {pattern = "Увеличение вероятности критического эффекта ваших заклинаний светлой магии на (%d+)%%%.", effect = "HOLYCRIT"}, 84 | {pattern = "Повышает вероятность критического эффекта ваших заклинаний светлой магии на (%d+)%%%.", effect = "HOLYCRIT"}, 85 | {pattern = "Увеличивает вероятность нанести критический удар на (%d+)%%%.", effect = "CRIT"}, 86 | {pattern = "Увеличение вероятности критического урона метательным оружием на (%d+)%%%.", effect = "RANGEDCRIT"}, 87 | {pattern = "Увеличивает урон, наносимый заклинаниями и эффектами тайной магии не более чем на (%d+)%.", effect = "ARCANEDMG"}, 88 | {pattern = "Увеличивает урон, наносимый заклинаниями и эффектами магии огня не более чем на (%d+)%.", effect = "FIREDMG"}, 89 | {pattern = "Увеличивает урон, наносимый заклинаниями и эффектами магии льда не более чем на (%d+)%.", effect = "FROSTDMG"}, 90 | {pattern = "Увеличивает урон, наносимый заклинаниями и эффектами светлой магии не более чем на (%d+)%.", effect = "HOLYDMG"}, 91 | {pattern = "Увеличивает урон, наносимый заклинаниями и эффектами сил природы не более чем на (%d+)%.", effect = "NATUREDMG"}, 92 | {pattern = "Увеличивает урон, наносимый заклинаниями и эффектами темной магии не более чем на (%d+)%.", effect = "SHADOWDMG"}, 93 | {pattern = "Увеличивает исцеляющие действия эффектов и заклинаний не более чем на (%d+)%.", effect = "HEAL"}, 94 | {pattern = "Увеличивает урон и исцеляющие действия магических эффектов и заклинаний не более чем на (%d+)%.", effect = {"HEAL", "DMG"}}, 95 | {pattern = "Повышение не более чем на (%d+) ед%. урона, наносимого нежити заклинаниями и магическими эффектами%.", effect = "DMGUNDEAD"}, 96 | {pattern = "Увеличение силы атаки на (%d+) ед%. в бою с нежитью%.", effect = "ATTACKPOWERUNDEAD"}, 97 | {pattern = "Восполняет (%d+) ед%. здоровья каждые 5 сек%.", effect = "HEALTHREG"}, 98 | {pattern = "Восполнение (%d+) ед%. здоровья раз в 5 сек%.", effect = "HEALTHREG"}, -- both versions ('per' and 'every') seem to be used 99 | {pattern = "Восполнение (%d+) ед%. маны раз в 5 сек%.", effect = "MANAREG"}, 100 | {pattern = "Восполнение (%d+) ед%. маны раз в 5 сек%.", effect = "MANAREG"}, 101 | {pattern = "Повышает меткость на (%d+)%%%.", effect = "TOHIT"}, 102 | {pattern = "Повышает меткость заклинаний на (%d+)%%%.", effect = "SPELLTOHIT"}, 103 | {pattern = "Снижает сопротивление магии у целей ваших заклинаний на (%d+).", effect = "SPELLPEN"}, 104 | {pattern = "Увеличивает защиту на (%d+).", effect = "DEFENSE"}, 105 | 106 | -- Added for HealPoints 107 | { pattern = "Во время произнесения заклинаний мана восполняется со скоростью%, равной (%d+)%% от обычной%.", effect = "CASTINGREG"}, 108 | { pattern = "Повышает вероятность критического эффекта заклинаний сил природы на (%d+)%%%.", effect = "NATURECRIT"}, 109 | { pattern = "Сокращает время произнесения заклинания \"Восстановление\" на 0%.(%d+) сек%.", effect = "CASTINGREGROWTH"}, 110 | { pattern = "Сокращает время произнесения заклинания \"Свет небес\" на 0%.(%d+) сек%.", effect = "CASTINGHOLYLIGHT"}, 111 | { pattern = "Уменьшает время применения заклинания \"Целительное прикосновение\" на 0%.(%d+) сек%.", effect = "CASTINGHEALINGTOUCH"}, 112 | { pattern = "Время произнесения заклинания \"Быстрое исцеление\" снижается на 0%.(%d+) сек%.", effect = "CASTINGFLASHHEAL"}, 113 | { pattern = "Время наложения заклинания \"Цепное исцеление\" снижено на 0%.(%d+) сек%.", effect = "CASTINGCHAINHEAL"}, 114 | { pattern = "Увеличение длительности заклинания \"Омоложение\" на (%d+) сек%.", effect = "DURATIONREJUV"}, 115 | { pattern = "Увеличение длительности заклинания \"Обновление\" на (%d+) сек%.", effect = "DURATIONRENEW"}, 116 | { pattern = "Повышение нормальной скорости восполнения здоровья и маны заклинателя на (%d+) ед%.", effect = "MANAREGNORMAL"}, 117 | { pattern = "Увеличивает эффект вашего заклинания \"Цепное исцеление\" на цели после первой на (%d+)%%%.", effect = "IMPCHAINHEAL"}, 118 | { pattern = "Увеличивает исцеляющий эффект заклинания \"Омоложение\" не более чем на (%d+) ед%.", effect = "IMPREJUVENATION"}, 119 | { pattern = "Увеличивает исцеляющий эффект заклинания \"Малая волна исцеления\" не более чем на (%d+) ед%.", effect = "IMPLESSERHEALINGWAVE"}, 120 | { pattern = "Увеличивает эффективность исцеления заклинания \"Вспышка Света\" на (%d+) ед%.", effect = "IMPFLASHOFLIGHT"}, 121 | { pattern = "После произнесения заклинаний \"Волна исцеления\" или \"Малая волна исцеления\"%, заклинатель с вероятностью 25%% восстанавливает (%d+)%% маны от базового расхода на заклинание%.", effect = "REFUNDHEALINGWAVE"}, 122 | { pattern = "Исцеление множественных целей заклинанием \"Волна исцеления\"%, способным распространяться на соседние цели%. Каждый из двух возможных переходов на соседнюю цель снижает эффект на (%d+)%%%.", effect = "JUMPHEALINGWAVE"}, 123 | { pattern = "Снижает затраты маны на заклинания \"Целительное прикосновение\"%, \"Омоложение\"%, \"Восстановление\" и \"Спокойствие\" на (%d+)%%%.", effect = "CHEAPERDRUID"}, 124 | { pattern = "При критическом действии заклинания \"Целительное прикосновение\" у вас восстановится (%d+)%% маны, затраченной на него%.", effect = "REFUNDHTCRIT"}, 125 | { pattern = "Снижает затраты маны на ваше заклинание \"Обновление\" на (%d+)%%%.", effect = "CHEAPERRENEW"}, 126 | }; 127 | 128 | -- generic patterns have the form "+xx bonus" or "bonus +xx" with an optional % sign after the value. 129 | 130 | -- first the generic bonus string is looked up in the following table 131 | PATTERNS_GENERIC_LOOKUP = { 132 | ["ко всем характеристикам"] = {"STR", "AGI", "STA", "INT", "SPI"}, 133 | ["к силе"] = "STR", 134 | ["к ловкости"] = "AGI", 135 | ["к выносливости"] = "STA", 136 | ["к интеллекту"] = "INT", 137 | ["к духу"] = "SPI", 138 | 139 | ["ко всем видам сопротивления"] = { "ARCANERES", "FIRERES", "FROSTRES", "NATURERES", "SHADOWRES"}, 140 | 141 | ["Рыбная ловля"] = "FISHING", 142 | ["Приманка"] = "FISHING", 143 | ["Навык рыбной ловли увеличивается на"] = "FISHING", 144 | ["к навыку горного дела"] = "MINING", 145 | ["к навыку травничества"] = "HERBALISM", 146 | ["к навыку снятия шкур"] = "SKINNING", 147 | ["к защите"] = "DEFENSE", 148 | ["Increased Defense"] = "DEFENSE", --? 149 | 150 | ["к силе атаки"] = "ATTACKPOWER", 151 | ["ед. в бою с нежитью."] = "ATTACKPOWERUNDEAD", 152 | ["ед. в облике кошки, медведя, лютого медведя."] = "ATTACKPOWERFERAL", 153 | 154 | ["к уклонению"] = "DODGE", 155 | ["к блокированию"] = "BLOCK", 156 | ["к блокированию"] = "BLOCKVALUE", 157 | ["к меткости"] = "TOHIT", 158 | ["к меткости заклинаний"] = "SPELLTOHIT", 159 | ["к блокированию"] = "BLOCK", 160 | ["к силе атаки дальнего боя"] = "RANGEDATTACKPOWER", 161 | ["ед. здоровья каждые 5 секунд"] = "HEALTHREG", 162 | ["к лечению"] = "HEAL", 163 | ["к лечению"] = "HEAL", 164 | ["к лечению и урону от заклинаний"] = {"HEAL", "DMG"}, 165 | ["к лечению и урону от заклинаний"] = {"HEAL", "DMG"}, 166 | ["к урону от заклинаний и лечению"] = {"HEAL", "DMG"}, 167 | ["ед. маны каждые 5 секунд"] = "MANAREG", 168 | ["ед. маны каждые"] = "MANAREG", 169 | ["к урону от заклинаний"] = {"HEAL", "DMG"}, 170 | ["к критическому удару"] = "CRIT", 171 | ["к критическому удару"] = "CRIT", 172 | ["к урону"] = "DMG", 173 | ["к здоровью"] = "HEALTH", 174 | ["здоровья"] = "HEALTH", 175 | ["к мане"] = "MANA", 176 | ["к броне"] = "ARMOR", 177 | ["Доспех усилен"] = "ARMOR", 178 | }; 179 | 180 | -- next we try to match against one pattern of stage 1 and one pattern of stage 2 and concatenate the effect strings 181 | PATTERNS_GENERIC_STAGE1 = { 182 | {pattern = "тайной магии", effect = "ARCANE"}, 183 | {pattern = "огня", effect = "FIRE"}, 184 | {pattern = "льда", effect = "FROST"}, 185 | {pattern = "светлой магии", effect = "HOLY"}, 186 | {pattern = "темной магии", effect = "SHADOW"}, 187 | {pattern = "сил природы", effect = "NATURE"} 188 | }; 189 | 190 | PATTERNS_GENERIC_STAGE2 = { 191 | {pattern = "сопротивление", effect = "RES"}, 192 | {pattern = "урон", effect = "DMG"}, 193 | {pattern = "эффект", effect = "DMG"}, 194 | }; 195 | 196 | -- finally if we got no match, we match against some special enchantment patterns. 197 | PATTERNS_OTHER = { 198 | {pattern = "Восполнение (%d+) ед%. маны каждые 5 сек%.", effect = "MANAREG"}, 199 | 200 | {pattern = "Слабое волшебное масло", effect = {"DMG", "HEAL"}, value = 8}, 201 | {pattern = "Малое волшебное масло", effect = {"DMG", "HEAL"}, value = 16}, 202 | {pattern = "Волшебное масло", effect = {"DMG", "HEAL"}, value = 24}, 203 | {pattern = "Сверкающее волшебное масло", effect = {"DMG", "HEAL", "SPELLCRIT"}, value = {36, 36, 1}}, 204 | 205 | {pattern = "Слабое масло маны", effect = "MANAREG", value = 4}, 206 | {pattern = "Малое масло маны", effect = "MANAREG", value = 8}, 207 | {pattern = "Сверкающее масло маны", effect = { "MANAREG", "HEAL"}, value = {12, 25}}, 208 | 209 | {pattern = "Этерниевая леска", effect = "FISHING", value = 5}, 210 | 211 | {pattern = "%+31 к лечению и 5 ед%. маны каждые 5 секунд", effect = { "MANAREG", "HEAL"}, value = {5, 31}}, 212 | {pattern = "%+16 к выносливости и %+100 к броне", effect = { "STA", "ARMOR"}, value = {16, 100}}, 213 | {pattern = "%+26 к силе атаки и %+1%% к критическому удару", effect = { "ATTACKPOWER", "CRIT"}, value = {26, 1}}, 214 | {pattern = "%+15 к урону от заклинаний и %+1%% к критическому удару заклинаниями", effect = { "DMG", "HEAL", "SPELLCRIT"}, value = {15, 15, 1}}, 215 | } 216 | } end) 217 | -------------------------------------------------------------------------------- /libs/RosterLib-2.0/RosterLib-2.0.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Name: RosterLib-2.0 3 | Revision: $Revision: 16213 $ 4 | X-ReleaseDate: $Date: 2006-08-10 08:55:29 +0200 (Thu, 10 Aug 2006) $ 5 | Author: Maia (maia.proudmoore@gmail.com) 6 | Website: http://wiki.wowace.com/index.php/RosterLib-2.0 7 | Documentation: http://wiki.wowace.com/index.php/RosterLib-2.0_API_Documentation 8 | SVN: http://svn.wowace.com/root/trunk/RosterLib-2.0/ 9 | Description: party/raid roster management 10 | Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0 11 | ]] 12 | 13 | local MAJOR_VERSION = "RosterLib-2.0" 14 | local MINOR_VERSION = "$Revision: 16213 $" 15 | 16 | if not AceLibrary then error(vmajor .. " requires AceLibrary.") end 17 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end 18 | if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end 19 | if not AceLibrary:HasInstance("AceEvent-2.0") then error(MAJOR_VERSION .. " requires AceEvent-2.0") end 20 | 21 | local updatedUnits = {} 22 | local unknownUnits = {} 23 | local RosterLib = {} 24 | local roster 25 | 26 | ------------------------------------------------ 27 | -- activate, enable, disable 28 | ------------------------------------------------ 29 | 30 | local function print(text) 31 | ChatFrame3:AddMessage(text) 32 | end 33 | 34 | local function activate(self, oldLib, oldDeactivate) 35 | RosterLib = self 36 | if oldLib then 37 | self.roster = oldLib.roster 38 | oldLib:UnregisterAllEvents() 39 | oldLib:CancelAllScheduledEvents() 40 | end 41 | if not self.roster then self.roster = {} end 42 | if oldDeactivate then oldDeactivate(oldLib) end 43 | roster = self.roster 44 | end 45 | 46 | 47 | local function external(self, major, instance) 48 | if major == "AceEvent-2.0" then 49 | AceEvent = instance 50 | AceEvent:embed(self) 51 | self:UnregisterAllEvents() 52 | self:CancelAllScheduledEvents() 53 | if AceEvent:IsFullyInitialized() then 54 | self:AceEvent_FullyInitialized() 55 | else 56 | self:RegisterEvent("AceEvent_FullyInitialized", "AceEvent_FullyInitialized", true) 57 | end 58 | elseif major == "Compost-2.0" then 59 | Compost = instance 60 | end 61 | end 62 | 63 | 64 | function RosterLib:Enable() 65 | -- not used anymore, but as addons still might be calling this method, we're keeping it. 66 | end 67 | 68 | 69 | function RosterLib:Disable() 70 | -- not used anymore, but as addons still might be calling this method, we're keeping it. 71 | end 72 | 73 | ------------------------------------------------ 74 | -- Internal functions 75 | ------------------------------------------------ 76 | 77 | function RosterLib:AceEvent_FullyInitialized() 78 | self:TriggerEvent("RosterLib_Enabled") 79 | self:RegisterEvent("RAID_ROSTER_UPDATE","ScanFullRoster") 80 | self:RegisterEvent("PARTY_MEMBERS_CHANGED","ScanFullRoster") 81 | self:RegisterEvent("UNIT_PET","ScanPet") 82 | self:ScanFullRoster() 83 | end 84 | 85 | 86 | ------------------------------------------------ 87 | -- Unit iterator 88 | ------------------------------------------------ 89 | 90 | local playersent, petsent, unitcount, petcount, pmem, rmem, unit 91 | 92 | local function NextUnit() 93 | -- STEP 1: pet 94 | if not petsent then 95 | petsent = true 96 | if rmem == 0 then 97 | unit = "pet" 98 | if UnitExists(unit) then return unit end 99 | end 100 | end 101 | -- STEP 2: player 102 | if not playersent then 103 | playersent = true 104 | if rmem == 0 then 105 | unit = "player" 106 | if UnitExists(unit) then return unit end 107 | end 108 | end 109 | -- STEP 3: raid units 110 | if rmem > 0 then 111 | -- STEP 3a: pet units 112 | for i = petcount, rmem do 113 | unit = string.format("raidpet%d", i) 114 | petcount = petcount + 1 115 | if UnitExists(unit) then return unit end 116 | end 117 | -- STEP 3b: player units 118 | for i = unitcount, rmem do 119 | unit = string.format("raid%d", i) 120 | unitcount = unitcount + 1 121 | if UnitExists(unit) then return unit end 122 | end 123 | -- STEP 4: party units 124 | elseif pmem > 0 then 125 | -- STEP 3a: pet units 126 | for i = petcount, pmem do 127 | unit = string.format("partypet%d", i) 128 | petcount = petcount + 1 129 | if UnitExists(unit) then return unit end 130 | end 131 | -- STEP 3b: player units 132 | for i = unitcount, pmem do 133 | unit = string.format("party%d", i) 134 | unitcount = unitcount + 1 135 | if UnitExists(unit) then return unit end 136 | end 137 | end 138 | end 139 | 140 | local function UnitIterator() 141 | playersent, petsent, unitcount, petcount, pmem, rmem = false, false, 1, 1, GetNumPartyMembers(), GetNumRaidMembers() 142 | return NextUnit 143 | end 144 | 145 | ------------------------------------------------ 146 | -- Roster code 147 | ------------------------------------------------ 148 | 149 | 150 | function RosterLib:ScanFullRoster() 151 | -- save all units we currently have, this way we can check who to remove from roster later. 152 | local temp = Compost and Compost:Acquire() or {} 153 | for name in pairs(roster) do 154 | temp[name] = true 155 | end 156 | -- update data 157 | for unitid in UnitIterator() do 158 | local name = self:CreateOrUpdateUnit(unitid) 159 | -- we successfully added a unit, so we don't need to remove it next step 160 | if name then temp[name] = nil end 161 | end 162 | -- clear units we had in roster that either left the raid or are unknown for some reason. 163 | for name in pairs(temp) do 164 | self:RemoveUnit(name) 165 | end 166 | if Compost then Compost:Reclaim(temp) end 167 | self:ProcessRoster() 168 | end 169 | 170 | 171 | function RosterLib:ScanPet(owner) 172 | local unitid = self:GetPetFromOwner(owner) 173 | if not unitid then 174 | return 175 | elseif not UnitExists(unitid) then 176 | unknownUnits[unitid] = nil 177 | -- find the pet in the roster we need to delete 178 | for _,u in pairs(roster) do 179 | if u.unitid == unitid then 180 | self:RemoveUnit(u.name) 181 | end 182 | end 183 | else 184 | self:CreateOrUpdateUnit(unitid) 185 | end 186 | self:ProcessRoster() 187 | end 188 | 189 | 190 | function RosterLib:GetPetFromOwner(id) 191 | -- convert party3 crap to raid IDs when in raid. 192 | local owner = self:GetUnitIDFromUnit(id) 193 | if not owner then 194 | return 195 | end 196 | -- get ID 197 | if string.find(owner,"raid") then 198 | return string.gsub(owner, "raid", "raidpet") 199 | elseif string.find(owner,"party") then 200 | return string.gsub(owner, "party", "partypet") 201 | elseif owner == "player" then 202 | return "pet" 203 | else 204 | return nil 205 | end 206 | end 207 | 208 | 209 | function RosterLib:ScanUnknownUnits() 210 | local name 211 | for unitid in pairs(unknownUnits) do 212 | if UnitExists(unitid) then 213 | name = self:CreateOrUpdateUnit(unitid) 214 | else 215 | unknownUnits[unitid] = nil 216 | end 217 | -- some pets never have a name. too bad for them, farewell! 218 | if not name and string.find(unitid,"pet") then 219 | unknownUnits[unitid] = nil 220 | end 221 | end 222 | self:ProcessRoster() 223 | end 224 | 225 | 226 | function RosterLib:ProcessRoster() 227 | if next(updatedUnits, nil) then 228 | self:TriggerEvent("RosterLib_RosterChanged", updatedUnits) 229 | for name in pairs(updatedUnits) do 230 | local u = updatedUnits[name] 231 | self:TriggerEvent("RosterLib_UnitChanged", u.unitid, u.name, u.class, u.subgroup, u.rank, u.oldname, u.oldunitid, u.oldclass, u.oldsubgroup, u.oldrank) 232 | if Compost then Compost:Reclaim(updatedUnits[name]) end 233 | updatedUnits[name] = nil 234 | end 235 | end 236 | if next(unknownUnits, nil) then 237 | self:CancelScheduledEvent("ScanUnknownUnits") 238 | self:ScheduleEvent("ScanUnknownUnits",self.ScanUnknownUnits, 1, self) 239 | end 240 | end 241 | 242 | 243 | function RosterLib:CreateOrUpdateUnit(unitid) 244 | local old = nil 245 | -- check for name 246 | local name = UnitName(unitid) 247 | if name and name ~= UNKNOWNOBJECT and name ~= UKNOWNBEING and not UnitIsCharmed(unitid) then 248 | -- clear stuff 249 | unknownUnits[unitid] = nil 250 | -- return if a pet attempts to replace a player name 251 | -- this doesnt fix the problem with 2 pets overwriting each other FIXME 252 | if string.find(unitid,"pet") then 253 | if roster[name] and roster[name].class ~= "pet" then 254 | return name 255 | end 256 | end 257 | -- save old data if existing 258 | if roster[name] then 259 | old = Compost and Compost:Acquire() or {} 260 | old.name = roster[name].name 261 | old.unitid = roster[name].unitid 262 | old.class = roster[name].class 263 | old.rank = roster[name].rank 264 | old.subgroup = roster[name].subgroup 265 | old.online = roster[name].online 266 | end 267 | -- object 268 | if not roster[name] then 269 | roster[name] = Compost and Compost:Acquire() or {} 270 | end 271 | -- name 272 | roster[name].name = name 273 | -- unitid 274 | roster[name].unitid = unitid 275 | -- class 276 | if string.find(unitid,"pet") then 277 | roster[name].class = "PET" 278 | else 279 | _,roster[name].class = UnitClass(unitid) 280 | end 281 | -- subgroup and rank 282 | if GetNumRaidMembers() > 0 then 283 | local _,_,num = string.find(unitid, "(%d+)") 284 | _,roster[name].rank,roster[name].subgroup = GetRaidRosterInfo(num) 285 | else 286 | roster[name].subgroup = 1 287 | roster[name].rank = 0 288 | end 289 | -- online/offline status 290 | roster[name].online = UnitIsConnected(unitid) 291 | 292 | -- compare data 293 | if not old 294 | or roster[name].name ~= old.name 295 | or roster[name].unitid ~= old.unitid 296 | or roster[name].class ~= old.class 297 | or roster[name].subgroup ~= old.subgroup 298 | or roster[name].rank ~= old.rank 299 | or roster[name].online ~= old.online 300 | then 301 | updatedUnits[name] = Compost and Compost:Acquire() or {} 302 | updatedUnits[name].oldname = (old and old.name) or nil 303 | updatedUnits[name].oldunitid = (old and old.unitid) or nil 304 | updatedUnits[name].oldclass = (old and old.class) or nil 305 | updatedUnits[name].oldsubgroup = (old and old.subgroup) or nil 306 | updatedUnits[name].oldrank = (old and old.rank) or nil 307 | updatedUnits[name].oldonline = (old and old.online) or nil 308 | updatedUnits[name].name = roster[name].name 309 | updatedUnits[name].unitid = roster[name].unitid 310 | updatedUnits[name].class = roster[name].class 311 | updatedUnits[name].subgroup = roster[name].subgroup 312 | updatedUnits[name].rank = roster[name].rank 313 | updatedUnits[name].online = roster[name].online 314 | end 315 | -- compost our table 316 | if old and Compost then 317 | Compost:Reclaim(old) 318 | end 319 | return name 320 | else 321 | unknownUnits[unitid] = true 322 | return false 323 | end 324 | end 325 | 326 | 327 | function RosterLib:RemoveUnit(name) 328 | updatedUnits[name] = Compost and Compost:Acquire() or {} 329 | updatedUnits[name].oldname = roster[name].name 330 | updatedUnits[name].oldunitid = roster[name].unitid 331 | updatedUnits[name].oldclass = roster[name].class 332 | updatedUnits[name].oldsubgroup = roster[name].subgroup 333 | updatedUnits[name].oldrank = roster[name].rank 334 | if Compost then Compost:Reclaim(roster[name]) end 335 | roster[name] = nil 336 | end 337 | 338 | 339 | ------------------------------------------------ 340 | -- API 341 | ------------------------------------------------ 342 | 343 | function RosterLib:GetUnitIDFromName(name) 344 | if roster[name] then 345 | return roster[name].unitid 346 | else 347 | return nil 348 | end 349 | end 350 | 351 | 352 | function RosterLib:GetUnitIDFromUnit(unit) 353 | local name = UnitName(unit) 354 | if name and roster[name] then 355 | return roster[name].unitid 356 | else 357 | return nil 358 | end 359 | end 360 | 361 | 362 | function RosterLib:GetUnitObjectFromName(name) 363 | if roster[name] then 364 | return roster[name] 365 | else 366 | return nil 367 | end 368 | end 369 | 370 | 371 | function RosterLib:GetUnitObjectFromUnit(unit) 372 | local name = UnitName(unit) 373 | if roster[name] then 374 | return roster[name] 375 | else 376 | return nil 377 | end 378 | end 379 | 380 | 381 | function RosterLib:IterateRoster(pets) 382 | local key 383 | return function() 384 | repeat 385 | key = next(roster, key) 386 | until (roster[key] == nil or pets or roster[key].class ~= "PET") 387 | 388 | return roster[key] 389 | end 390 | end 391 | 392 | 393 | AceLibrary:Register(RosterLib, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) 394 | -------------------------------------------------------------------------------- /localization.lua: -------------------------------------------------------------------------------- 1 | local L = AceLibrary("AceLocale-2.2"):new("NotGrid") 2 | 3 | L:RegisterTranslations("enUS", function() return { 4 | ["Dead"] = true, 5 | ["Ghost"] = true, 6 | ["Scroll Me!"] = true, 7 | 8 | ["Unit Width"] = true, 9 | ["Unit Height"] = true, 10 | ["Unit Border"] = true, 11 | ["Unit Padding"] = true, 12 | ["Font"] = true, 13 | ["Texture"] = true, 14 | ["Name Color"] = true, 15 | ["Name Size"] = true, 16 | ["Name Length"] = true, 17 | ["Health Color"] = true, 18 | ["Health Threshold"] = true, 19 | ["Highlight Target"] = true, 20 | ["Aggro Warning"] = true, 21 | ["Mana Warning"] = true, 22 | ["Healcomm Bar"] = true, 23 | ["Healcomm Text"] = true, 24 | ["Top Left Icon"] = true, 25 | ["Top Icon"] = true, 26 | ["Top Right Icon"] = true, 27 | ["Right Icon"] = true, 28 | ["Bottom Right Icon"] = true, 29 | ["Bottom Icon"] = true, 30 | ["Bottom Left Icon"] = true, 31 | ["Left Icon"] = true, 32 | ["Icon Size"] = true, 33 | ["Proximity Leeway"] = true, 34 | ["Use Map Proximity"] = true, 35 | ["Smart Center"] = true, 36 | ["Show While Solo"] = true, 37 | ["Show In Party"] = true, 38 | ["Show Party In Raid"] = true, 39 | ["Disable Tooltip In Combat"] = true, 40 | ["Health Orientation"] = true, 41 | ["Show Blizz Frames"] = true, 42 | ["Growth Direction"] = true, 43 | ["Show Power Bar"] = true, 44 | ["Power Position"] = true, 45 | ["Power Size"] = true, 46 | ["Config Mode"] = true, 47 | ["Background"] = true, 48 | ["Show Pets"] = true, 49 | ["Custom Pet Color"] = true, 50 | ["TBC Shaman Color"] = true, 51 | ["Proximity Rate"] = true, 52 | ["Health Background"] = true, 53 | ["Clique Hook"] = true, 54 | ["Power Background"] = true, 55 | ["Position"] = true, 56 | ["Border Artwork"] = true, 57 | ["Name Position"] = true, 58 | ["Healcomm Text Position"] = true, 59 | ["Version Checking"] = true, 60 | ["Draggable"] = true, 61 | 62 | ["CombatEvents"] = { 63 | ["CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS"] = "(%a+) gains %a.+", --%a on the last just to make sure its not a digit 64 | ["CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE"] = "(%a+) is afflicted by .+", 65 | ["CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS"] = "(%a+) gains %a.+", 66 | ["CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE"] = "(%a+) is afflicted by .+", 67 | 68 | ["CHAT_MSG_SPELL_PARTY_BUFF"] = "(%a+) begins .+", --I don't get this message for party members? Only friendly? 69 | ["CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF"] = "(%a+) begins .+", 70 | ["CHAT_MSG_SPELL_PARTY_DAMAGE"] = "(%a+) begins .+", 71 | ["CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE"] = "(%a+) begins .+", 72 | 73 | ["CHAT_MSG_SPELL_AURA_GONE_PARTY"] = ".+ fades from (%a+)%.", 74 | ["CHAT_MSG_SPELL_AURA_GONE_OTHER"] = ".+ fades from (%a+)%.", -- will pick up hostile fades as well as freind, but I won't have them in rosterlib so whatevs 75 | 76 | ["CHAT_MSG_SPELL_SELF_BUFF"] = "Your .+ heals (%a+) for .+" 77 | }, 78 | 79 | -------------- 80 | -- Tooltips -- 81 | -------------- 82 | 83 | ["pet_tooltip"] = "Note: Prone to visual errors.", 84 | ["classcolor_tooltip"] = "Toggle for class color.", 85 | ["smartcenter_tooltip"] = "As your group expands the frames stay horizontally centered on the original group placement.", 86 | ["healththreshold_tooltip"] = "Health percentage before name is replaced with health deficit.", 87 | ["manathreshhold_tooltip"] = "Mana percentage before border color changes.", 88 | ["proximityleeway_tooltip"] = "Amount of seconds to be considered \"In Range\" after a positive confirmation.", 89 | ["proximityrate_tooltip"] = "Amount of seconds between proximity checks.", 90 | ["cliquehook_tooltip"] = "Hooks the Clique spellcast function to use NG instead for proximity checking beyond 28 yards within instances. Toggling will reload UI.", 91 | ["powercolor_tooltip"] = "Toggle for power color.", 92 | ["position_tooltip"] = "Shift+Ctrl = 100\nShift = 10", 93 | ["draggable_tooltip"] = "Note: Possible client crash bug\n Smart Center disabled", 94 | ["icon_tooltip"] = "Toggle to invert icon display.", 95 | 96 | 97 | } end) 98 | 99 | L:RegisterTranslations("ruRU", function() return { 100 | ["Dead"] = "Мертв", 101 | ["Ghost"] = "Призрак", 102 | ["Scroll Me!"] = "Прокрути меня!", 103 | 104 | ["Unit Width"] = "Ширина окон", 105 | ["Unit Height"] = "Высота окон", 106 | ["Unit Border"] = "Граница окон", 107 | ["Unit Padding"] = "Интервал окон", 108 | ["Font"] = "Шрифт", 109 | ["Texture"] = "Текстура", 110 | ["Name Color"] = "Цвет имени", 111 | ["Name Size"] = "Размер имени", 112 | ["Name Length"] = "Длина имени", 113 | ["Health Color"] = "Цвет здоровья", 114 | ["Health Threshold"] = "Порог здоровья", 115 | ["Highlight Target"] = "Выделение цели", 116 | ["Aggro Warning"] = "Предупреждение аггро", 117 | ["Mana Warning"] = "Предупреждение маны", 118 | ["Healcomm Bar"] = "Полоса входящего исцеления", 119 | ["Healcomm Text"] = "Текст входящего исцеления", 120 | ["Top Left Icon"] = "Значек сверху слева", 121 | ["Top Icon"] = "Значек сверху", 122 | ["Top Right Icon"] = "Значек сверху справа", 123 | ["Right Icon"] = "Значек справа", 124 | ["Bottom Right Icon"] = "Значек снизу справа", 125 | ["Bottom Icon"] = "Значек снизу", 126 | ["Bottom Left Icon"] = "Значек снизу слева", 127 | ["Left Icon"] = "Значек слева", 128 | ["Icon Size"] = "Размер значка", 129 | ["Proximity Leeway"] = "Proximity Leeway", -- 130 | ["Use Map Proximity"] = "Использовать карту приближения", 131 | ["Smart Center"] = "Умный центр", 132 | ["Show While Solo"] = "Показать вне группы", 133 | ["Show In Party"] = "Показать в группе", 134 | ["Show Party In Raid"] = "Показать группы в рейде", 135 | ["Disable Tooltip In Combat"] = "Отключить всплывающую подсказку в бою", 136 | ["Health Orientation"] = "Ориентация здоровья", 137 | ["Show Blizz Frames"] = "Показать окна Blizzard", 138 | ["Growth Direction"] = "Направление роста", 139 | ["Show Power Bar"] = "Показать полосу силы", 140 | ["Power Position"] = "Положение полосы силы", 141 | ["Power Size"] = "Размер полосы силы", 142 | ["Config Mode"] = "Режим настройки", 143 | ["Background"] = "Задний фон", 144 | ["Show Pets"] = "Показать питомцев", 145 | ["Custom Pet Color"] = "Пользовательский цвет питомца", 146 | ["TBC Shaman Color"] = "Пользовательский цвет шамана - TBC", 147 | ["Proximity Rate"] = "Коэффициент близости", 148 | ["Health Background"] = "Фон здоровья", 149 | ["Clique Hook"] = "Захват Clique", 150 | ["Power Background"] = "Фон полосы силы", 151 | ["Position"] = "Положение", 152 | ["Border Artwork"] = "Рисунок границ", 153 | ["Name Position"] = "Положение имени", 154 | ["Healcomm Text Position"] = "Положение текста Healcomm", 155 | ["Version Checking"] = "Проверка версии", 156 | ["Draggable"] = "Перетаскиваемый", 157 | 158 | ["CombatEvents"] = { 159 | ["CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS"] = "(%a+) получает эффект %a.+", 160 | ["CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE"] = "(%a+) находится под воздействием эффекта .+", 161 | ["CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS"] = "(%a+) получает эффект %a.+", 162 | ["CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE"] = "(%a+) находится под воздействием эффекта .+", 163 | 164 | ["CHAT_MSG_SPELL_PARTY_BUFF"] = "(%a+) начинает .+", 165 | ["CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF"] = "(%a+) начинает .+", 166 | ["CHAT_MSG_SPELL_PARTY_DAMAGE"] = "(%a+) начинает .+", 167 | ["CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE"] = "(%a+) начинает .+", 168 | 169 | ["CHAT_MSG_SPELL_AURA_GONE_PARTY"] = "Действие эффекта \".+\", наложенного на (%a+), заканчивается%.", 170 | ["CHAT_MSG_SPELL_AURA_GONE_OTHER"] = "Действие эффекта \".+\", наложенного на (%a+), заканчивается%.", 171 | 172 | ["CHAT_MSG_SPELL_SELF_BUFF"] = "Ваше заклинание \".+\" исцеляет (%a+) на .+" 173 | }, 174 | 175 | -------------- 176 | -- Tooltips -- 177 | -------------- 178 | 179 | ["pet_tooltip"] = "Примечание: подвержен визуальным ошибкам.", 180 | ["classcolor_tooltip"] = "Вкл.\\Выкл. цвет класса", 181 | ["smartcenter_tooltip"] = "По мере расширения группы рамки остаются горизонтально по центру исходного расположения группы.", 182 | ["healththreshold_tooltip"] = "Процент здоровья перед именем заменяется дефицитом здоровья.", 183 | ["manathreshhold_tooltip"] = "Процент маны до изменения цвета бордюра.", 184 | ["proximityleeway_tooltip"] = "Количество секунд, которое будет учитывать \"в пределах досягаемости\" после положительного заклинания или подтверждения боевого журнала.", 185 | ["proximityrate_tooltip"] = "Количество секунд между проверками близости.", 186 | ["cliquehook_tooltip"] = "Захват функции произнесения заклинаний Clique, чтобы вместо этого использовать NG для проверки близости за пределами 28 ярдов внутри подземелий. Переключение приведет к перезагрузке пользовательского интерфейса.", 187 | ["powercolor_tooltip"] = "Переключить цвет полос силы.", 188 | ["position_tooltip"] = "Shift+Ctrl = 100\nShift = 10", 189 | ["draggable_tooltip"] = "Примечание. Возможен сбой клиента.\n Умный центр отключен", 190 | ["icon_tooltip"] = "Переключить, чтобы инвертировать отображение значков.", 191 | 192 | } end) 193 | -------------------------------------------------------------------------------- /mapsizes.lua: -------------------------------------------------------------------------------- 1 | -- extracted from WorldMapArea dbc table -- x is left/right, y is top/bottom -- areaname correlates to GetMapInfo() api call 2 | local Default = { 3 | ["Alterac"] = {x = 2800.0003, y = 1866.6667}, 4 | ["AlteracValley"] = {x = 4237.5, y = 2825}, 5 | ["Arathi"] = {x = 3600.0004, y = 2399.9997}, 6 | ["ArathiBasin"] = {x = 1756.2497, y = 1170.833}, 7 | ["Ashenvale"] = {x = 5766.667, y = 3843.7504}, 8 | ["Aszhara"] = {x = 5070.833, y = 3381.25}, 9 | ["Azeroth"] = {x = 35199.9, y = 23466.6}, 10 | ["Badlands"] = {x = 2487.5, y = 1658.334}, 11 | ["Barrens"] = {x = 10133.334, y = 6756.25}, 12 | ["BlastedLands"] = {x = 3350, y = 2233.33}, 13 | ["BurningSteppes"] = {x = 2929.1663, y = 1952.083}, 14 | ["Darkshore"] = {x = 6550, y = 4366.666}, 15 | ["Darnassis"] = {x = 1058.333, y = 705.733}, 16 | ["DeadwindPass"] = {x = 2499.9997, y = 1666.664}, 17 | ["Desolace"] = {x = 4495.833, y = 2997.9163}, 18 | ["DunMorogh"] = {x = 4925, y = 3283.334}, 19 | ["Durotar"] = {x = 5287.5, y = 3525}, 20 | ["Duskwood"] = {x = 2700.0003, y = 1800.004}, 21 | ["Dustwallow"] = {x = 5250.0001, y = 3500}, 22 | ["EasternPlaguelands"] = {x = 3870.833, y = 2581.25}, 23 | ["Elwynn"] = {x = 3470.834, y = 2314.587}, 24 | ["Felwood"] = {x = 5750, y = 3833.333}, 25 | ["Feralas"] = {x = 6950, y = 4633.333}, 26 | ["Hilsbrad"] = {x = 3200, y = 2133.333}, 27 | ["Hinterlands"] = {x = 3850, y = 2566.667}, 28 | ["Ironforge"] = {x = 790.6246, y = 527.605}, 29 | ["Kalimdor"] = {x = 36799.81, y = 24533.2}, 30 | ["LochModan"] = {x = 2758.333, y = 1839.583}, 31 | ["Moonglade"] = {x = 2308.333, y = 1539.583}, 32 | ["Mulgore"] = {x = 5137.5, y = 3425.0003}, 33 | ["Ogrimmar"] = {x = 1402.605, y = 935.416}, 34 | ["Redridge"] = {x = 2170.834, y = 1447.92}, 35 | ["SearingGorge"] = {x = 2231.2503, y = 1487.5}, 36 | ["Silithus"] = {x = 3483.334, y = 2322.916}, 37 | ["Silverpine"] = {x = 4200, y = 2800}, 38 | ["StonetalonMountains"] = {x = 4883.333, y = 3256.2503}, 39 | ["Stormwind"] = {x = 1344.27037, y = 896.354}, 40 | ["Stranglethorn"] = {x = 6381.25, y = 4254.17}, 41 | ["SwampOfSorrows"] = {x = 2293.75, y = 1529.167}, 42 | ["Tanaris"] = {x = 6900, y = 4600}, 43 | ["Teldrassil"] = {x = 5091.666, y = 3393.75}, 44 | ["ThousandNeedles"] = {x = 4399.9997, y = 2933.333}, 45 | ["ThunderBluff"] = {x = 1043.7499, y = 695.8331}, 46 | ["Tirisfal"] = {x = 4518.75, y = 3012.5001}, 47 | ["Undercity"] = {x = 959.375, y = 640.104}, 48 | ["UngoroCrater"] = {x = 3700.0003, y = 2466.666}, 49 | ["WarsongGulch"] = {x = 1145.8337, y = 764.5831}, 50 | ["WesternPlaguelands"] = {x = 4299.9997, y = 2866.667}, 51 | ["Westfall"] = {x = 3500.0003, y = 2333.33}, 52 | ["Wetlands"] = {x = 4135.4167, y = 2756.25}, 53 | ["Winterspring"] = {x = 7100.0003, y = 4733.333} 54 | } 55 | 56 | local Turtle_WoW = { 57 | ["AhnQiraj"] = {x = 977.56, y = 651.707}, 58 | ["AhnQiraj2f"] = {x = 2777.544, y = 1851.696}, 59 | ["AhnQirajEntrance"] = {x = 4139.02, y = 2946.05}, 60 | ["AlahThalas"] = {x = 1010.946, y = 677.151}, 61 | ["Alterac"] = {x = 2800.0003, y = 1866.6667}, 62 | ["AlteracValley"] = {x = 4237.5, y = 2825}, 63 | ["AlteracValleyClassic"] = {x = 4237.5, y = 2825}, 64 | ["AmaniAlor"] = {x = 1515, y = 997}, 65 | ["Arathi"] = {x = 3600.0004, y = 2399.9997}, 66 | ["ArathiBasin"] = {x = 1756.2497, y = 1170.833}, 67 | ["Ashenvale"] = {x = 5766.667, y = 3843.7504}, 68 | ["Aszhara"] = {x = 5070.833, y = 3381.25}, 69 | ["Azeroth"] = {x = 35199.9, y = 23466.6}, 70 | ["AzsharaCrater"] = {x = 4236, y = 695}, 71 | ["Badlands"] = {x = 2487.5, y = 1658.334}, 72 | ["Barrens"] = {x = 10133.334, y = 6756.25}, 73 | ["BlackFathomDeeps"] = {x = 1221.87, y = 806.42}, 74 | ["BlackrockDepths"] = {x = 1407.061, y = 938.0403}, 75 | ["BlackrockDepths2f"] = {x = 1507.061, y = 1004.7072}, 76 | ["BlackMorass"] = {x = 1271.991, y = 845.475}, 77 | ["BlackMorass2f"] = {x = 1085.859, y = 726.609}, 78 | ["BlackrockMountain"] = {x = 711.56, y = 468.68}, 79 | ["BlackrockSpire"] = {x = 886.839, y = 591.226}, 80 | ["BlackrockSpire2f"] = {x = 886.839, y = 591.226}, 81 | ["BlackrockSpire3f"] = {x = 886.839, y = 591.226}, 82 | ["BlackrockSpire4f"] = {x = 886.839, y = 591.226}, 83 | ["BlackrockSpire5f"] = {x = 886.839, y = 591.226}, 84 | ["BlackrockSpire6f"] = {x = 886.839, y = 591.226}, 85 | ["BlackrockSpire7f"] = {x = 886.839, y = 591.226}, 86 | ["BlackwingLair"] = {x = 499.428, y = 332.95}, 87 | ["BlackwingLair2f"] = {x = 649.427, y = 432.95}, 88 | ["BlackwingLair3f"] = {x = 649.427, y = 432.95}, 89 | ["BlackwingLair4f"] = {x = 649.427, y = 432.95}, 90 | ["BlastedLands"] = {x = 3350, y = 2233.33}, 91 | ["BurningSteppes"] = {x = 2929.1663, y = 1952.083}, 92 | ["CavernsOfTime"] = {x = 1348.242, y = 888.086}, 93 | ["Collin"] = {x = 37651.46, y = 25100.97}, 94 | ["CrescentGrove"] = {x = 2643.215, y = 1751.157}, 95 | ["Darkshore"] = {x = 6550, y = 4366.666}, 96 | ["Darnassis"] = {x = 1058.333, y = 705.733}, 97 | ["DeadminesEntrance"] = {x = 449.89, y = 299.92}, 98 | ["DeadwindPass"] = {x = 2499.9997, y = 1666.664}, 99 | ["DeeprunTram"] = {x = 312, y = 208}, 100 | ["DeeprunTram2f"] = {x = 309, y = 208}, 101 | ["Desolace"] = {x = 4495.833, y = 2997.9163}, 102 | ["DireMaul"] = {x = 1275, y = 850}, 103 | ["DireMaul2f"] = {x = 525, y = 350}, 104 | ["DireMaul3f"] = {x = 487.5, y = 325}, 105 | ["DireMaul4f"] = {x = 750, y = 500}, 106 | ["DireMaul5f"] = {x = 800.0008, y = 533.334}, 107 | ["DireMaul6f"] = {x = 975, y = 650}, 108 | ["DunMorogh"] = {x = 4925, y = 3283.334}, 109 | ["Durotar"] = {x = 5287.5, y = 3525}, 110 | ["Duskwood"] = {x = 2700.0003, y = 1800.004}, 111 | ["Dustwallow"] = {x = 5250.0001, y = 3500}, 112 | ["EasternPlaguelands"] = {x = 3870.833, y = 2581.25}, 113 | ["Elwynn"] = {x = 3470.834, y = 2314.587}, 114 | ["EmeraldSanctum"] = {x = 1273.101, y = 853.722}, 115 | ["EversongWoods"] = {x = 4925, y = 3283.337}, 116 | ["Felwood"] = {x = 5750, y = 3833.333}, 117 | ["Feralas"] = {x = 6950, y = 4633.333}, 118 | ["Ghostlands"] = {x = 3300, y = 2199.999}, 119 | ["Gillijim"] = {x = 2464.944, y = 1927.38}, 120 | ["Gilneas"] = {x = 3667.638, y = 2442.057}, 121 | ["GilneasCity"] = {x = 1250.19, y = 837.443}, 122 | ["Gnomeregan"] = {x = 769.668, y = 513.112}, 123 | ["Gnomeregan2f"] = {x = 769.668, y = 513.112}, 124 | ["Gnomeregan3f"] = {x = 869.668, y = 579.778}, 125 | ["Gnomeregan4f"] = {x = 869.6697, y = 579.78}, 126 | ["GnomereganEntrance"] = {x = 571.19, y = 379.14}, 127 | ["HateforgeQuarry"] = {x = 752.119, y = 510.335}, 128 | ["Hilsbrad"] = {x = 3200, y = 2133.333}, 129 | ["Hinterlands"] = {x = 3850, y = 2566.667}, 130 | ["Hyjal"] = {x = 3206.631, y = 2141.755}, 131 | ["Icepoint"] = {x = 1596.938, y = 1062.97}, 132 | ["Ironforge"] = {x = 790.6246, y = 527.605}, 133 | ["Kalimdor"] = {x = 36799.81, y = 24533.2}, 134 | ["Karazhan"] = {x = 598.041, y = 399.32}, 135 | ["KarazhanCrypt"] = {x = 546.75, y = 391.97}, 136 | ["Lapidis"] = {x = 2165.066, y = 2042.87}, 137 | ["LochModan"] = {x = 2758.333, y = 1839.583}, 138 | ["Maraudon"] = {x = 2112.09, y = 1410.89}, 139 | ["MaraudonEntrance"] = {x = 824, y = 550}, 140 | ["MoltenCore"] = {x = 1264.8, y = 843.199}, 141 | ["Moomoo"] = {x = 1007.68, y = 671.79}, 142 | ["Moonglade"] = {x = 2308.333, y = 1539.583}, 143 | ["Mulgore"] = {x = 5137.5, y = 3425.0003}, 144 | ["Naxxramas"] = {x = 1991.69, y = 1318.416}, 145 | ["Naxxramas2f"] = {x = 652.1, y = 439.67}, 146 | ["Ogrimmar"] = {x = 1402.605, y = 935.416}, 147 | ["OnyxiasLair"] = {x = 483.118, y = 322.0788}, 148 | ["Ragefire"] = {x = 738.864, y = 492.5762}, 149 | ["RazorfenDowns"] = {x = 709.049, y = 472.7}, 150 | ["RazorfenKraul"] = {x = 736.45, y = 490.96}, 151 | ["Redridge"] = {x = 2170.834, y = 1447.92}, 152 | ["RuinsofAhnQiraj"] = {x = 2512.5004, y = 1675}, 153 | ["ScarletEnclave"] = {x = 3172, y = 2115}, 154 | ["ScarletMonastery"] = {x = 619.984, y = 413.322}, 155 | ["ScarletMonastery2f"] = {x = 320.191, y = 213.4605}, 156 | ["ScarletMonastery3f"] = {x = 612.6966, y = 408.46}, 157 | ["ScarletMonastery4f"] = {x = 703.3, y = 468.8663}, 158 | ["ScarletMonasteryEntrance"] = {x = 203.66, y = 135.04}, 159 | ["Scholomance"] = {x = 320.0489, y = 213.365}, 160 | ["Scholomance2f"] = {x = 440.049, y = 293.3664}, 161 | ["Scholomance3f"] = {x = 410.078, y = 273.3858}, 162 | ["Scholomance4f"] = {x = 531.042, y = 354.0282}, 163 | ["SearingGorge"] = {x = 2231.2503, y = 1487.5}, 164 | ["ShadowfangKeep"] = {x = 352.43, y = 234.9534}, 165 | ["ShadowfangKeep2f"] = {x = 212.426, y = 141.618}, 166 | ["ShadowfangKeep3f"] = {x = 152.43, y = 101.61993}, 167 | ["ShadowfangKeep4f"] = {x = 152.43, y = 101.6247}, 168 | ["ShadowfangKeep5f"] = {x = 152.43, y = 101.6247}, 169 | ["ShadowfangKeep6f"] = {x = 198.43, y = 132.28661}, 170 | ["ShadowfangKeep7f"] = {x = 272.43, y = 181.61993}, 171 | ["Silithus"] = {x = 3483.334, y = 2322.916}, 172 | ["SilvermoonCity"] = {x = 1211.458, y = 806.772}, 173 | ["Silverpine"] = {x = 4200, y = 2800}, 174 | ["StonetalonMountains"] = {x = 4883.333, y = 3256.2503}, 175 | ["Stormwind"] = {x = 1737.50033, y = 1158.333}, 176 | ["StormwindVault"] = {x = 354.497, y = 234.738}, 177 | ["Stranglethorn"] = {x = 6381.25, y = 4254.17}, 178 | ["Stratholme"] = {x = 1185.344, y = 789.855}, 179 | ["Sunnyglade"] = {x = 988.626, y = 1393.165}, 180 | ["SwampOfSorrows"] = {x = 2293.75, y = 1529.167}, 181 | ["Tanaris"] = {x = 6900, y = 4600}, 182 | ["TelAbim"] = {x = 3154, y = 2174}, 183 | ["Teldrassil"] = {x = 5091.666, y = 3393.75}, 184 | ["TheDeadmines"] = {x = 656.59, y = 434.97}, 185 | ["TheStockade"] = {x = 378.153, y = 252.1025}, 186 | ["TheTempleOfAtalHakkar"] = {x = 695.029, y = 463.353}, 187 | ["TheTempleOfAtalHakkar2f"] = {x = 248.17677, y = 166.0355}, 188 | ["TheTempleOfAtalHakkar3f"] = {x = 556.1692, y = 370.388}, 189 | ["ThousandNeedles"] = {x = 4399.9997, y = 2933.333}, 190 | ["ThunderBluff"] = {x = 1043.7499, y = 695.8331}, 191 | ["Tirisfal"] = {x = 4518.75, y = 3012.5001}, 192 | ["Uldaman"] = {x = 893.668, y = 595.779}, 193 | ["UldamanEntrance"] = {x = 563.31, y = 376.1}, 194 | ["Undercity"] = {x = 959.375, y = 640.104}, 195 | ["UngoroCrater"] = {x = 3700.0003, y = 2466.666}, 196 | ["WailingCaverns"] = {x = 936.475, y = 624.316}, 197 | ["WailingCavernsEntrance"] = {x = 572.777, y = 381.849}, 198 | ["WarsongGulch"] = {x = 1145.8337, y = 764.5831}, 199 | ["WesternPlaguelands"] = {x = 4299.9997, y = 2866.667}, 200 | ["Westfall"] = {x = 3500.0003, y = 2333.33}, 201 | ["Wetlands"] = {x = 4135.4167, y = 2756.25}, 202 | ["Winterspring"] = {x = 7100.0003, y = 4733.333}, 203 | ["WinterVeilVale"] = {x = 1432, y = 977}, 204 | ["ZulFarrak"] = {x = 1383.3333, y = 922.916}, 205 | ["ZulGurub"] = {x = 2120.833, y = 1414.58} 206 | } 207 | 208 | function NotGrid:GetMapSizes() 209 | self.ProximityVars.MapSizes = Default 210 | local RealmName = GetRealmName() 211 | if RealmName == "Turtle WoW" or RealmName == "Tel'Abim" or RealmName == "Nordanaar" then 212 | self.ProximityVars.MapSizes = Turtle_WoW 213 | end 214 | end 215 | -------------------------------------------------------------------------------- /media/GridGradient.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnwl/NotGrid/466d1040a5dd53c87fa2c3b268d2e3e0bb13d71f/media/GridGradient.tga -------------------------------------------------------------------------------- /media/Striped.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnwl/NotGrid/466d1040a5dd53c87fa2c3b268d2e3e0bb13d71f/media/Striped.tga -------------------------------------------------------------------------------- /media/borderartwork.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnwl/NotGrid/466d1040a5dd53c87fa2c3b268d2e3e0bb13d71f/media/borderartwork.tga -------------------------------------------------------------------------------- /media/res.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnwl/NotGrid/466d1040a5dd53c87fa2c3b268d2e3e0bb13d71f/media/res.tga -------------------------------------------------------------------------------- /media/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnwl/NotGrid/466d1040a5dd53c87fa2c3b268d2e3e0bb13d71f/media/screenshot.jpg -------------------------------------------------------------------------------- /notgrid.toc: -------------------------------------------------------------------------------- 1 | ## Interface: 11200 2 | ## Title: NotGrid |cff7fff7f -Ace2-|r 3 | ## Notes: It's Not Grid 4 | ## Notes-ruRU: Это не Grid 5 | ## SavedVariablesPerCharacter: NotGridOptions 6 | 7 | Libs\AceLibrary\AceLibrary.lua 8 | Libs\AceLocale-2.2\AceLocale-2.2.lua 9 | Libs\AceOO-2.0\AceOO-2.0.lua 10 | libs\AceDebug-2.0\AceDebug-2.0.lua 11 | Libs\AceAddon-2.0\AceAddon-2.0.lua 12 | Libs\AceConsole-2.0\AceConsole-2.0.lua 13 | Libs\AceEvent-2.0\AceEvent-2.0.lua 14 | Libs\AceHook-2.1\AceHook-2.1.lua 15 | Libs\Compost-2.0\Compost-2.0.lua 16 | Libs\Gratuity-2.0\Gratuity-2.0.lua 17 | Libs\RosterLib-2.0\RosterLib-2.0.lua 18 | libs\Deformat-2.0\Deformat-2.0.lua 19 | libs\ItemBonusLib-1.0\Locales\enUS.lua 20 | libs\ItemBonusLib-1.0\Locales\frFR.lua 21 | libs\ItemBonusLib-1.0\Locales\deDE.lua 22 | libs\ItemBonusLib-1.0\Locales\ruRU.lua 23 | libs\ItemBonusLib-1.0\ItemBonusLib-1.0.lua 24 | Libs\HealComm-1.0\HealComm-1.0.lua 25 | Libs\Banzai-1.0\Banzai-1.0.lua 26 | 27 | localization.lua 28 | core.lua 29 | frames.lua 30 | mapsizes.lua 31 | proximity.lua 32 | options.lua 33 | menus.lua 34 | -------------------------------------------------------------------------------- /options.lua: -------------------------------------------------------------------------------- 1 | local L = AceLibrary("AceLocale-2.2"):new("NotGrid") 2 | 3 | local DefaultOptions = { 4 | ["version"] = 1.132, -- will be the commit number from now on. 5 | ["versionchecking"] = true, 6 | 7 | ["unitwidth"] = 36, 8 | ["unitheight"] = 36, 9 | ["unitborder"] = 2, 10 | ["unitpadding"] = 2, 11 | ["unitbgcolor"] = {0,0,0,0.4}, 12 | ["unitbordercolor"] = {0,0,0,0.8}, 13 | ["unithealthorientation"] = 1, 14 | ["unithealthbartexture"] = "Interface\\AddOns\\NotGrid\\media\\Striped", 15 | ["unithealthbarcolor"] = {39/255,186/255,42/255,1}, 16 | ["unithealthbarbgcolor"] = {0,0,0,0.1}, 17 | ["unithealthbarbgtexture"] = "Interface\\Buttons\\WHITE8X8", 18 | ["unitfont"] = "Fonts\\ARIALN.TTF", 19 | ["unitnamehealthtextcolor"] = {1,1,1,1}, 20 | ["unitnamehealthtextsize"] = 12, 21 | ["unithealcommbarcolor"] = {32/255,112/255,11/255,1}, 22 | ["unithealcommtextcolor"] = {39/255,186/255,42/255,1}, 23 | ["unithealcommtextsize"] = 10, 24 | ["unithealcommtextoffx"] = 0, 25 | ["unithealcommtextoffy"] = -10, 26 | ["unittrackingiconsize"] = 6, 27 | ["unittrackingiconborder"] = 1, 28 | ["unittrackingiconbordercolor"] = {0,0,0,1}, 29 | 30 | ["showpowerbar"] = false, 31 | ["powersize"] = 3, -- this will be width if the player chooses to make it Verical, or height if they make it Horizontal 32 | ["powerposition"] = 3, -- 1=top,2=bottom,3=left,4=right 33 | ["colorpowerbarbgbytype"] = false, 34 | ["unitpowerbarbgcolor"] = {0,0,0,0.1}, 35 | 36 | ["trackingicon1"] = {"Rejuvenation","Regrowth","Renew",}, -- potentially be better to have the auraname/spelltype be the key, but that introduces other problems to work around 37 | ["trackingicon1invert"] = false, 38 | ["trackingicon1color"] = {0.37,0.83,0.38}, 39 | ["trackingicon2"] = {"",}, 40 | ["trackingicon2invert"] = false, 41 | ["trackingicon2color"] = {0.20,0.60,1.00}, 42 | ["trackingicon3"] = {"Magic",}, 43 | ["trackingicon3invert"] = false, 44 | ["trackingicon3color"] = {0.20,0.60,1.00}, 45 | ["trackingicon4"] = {"Poison",}, 46 | ["trackingicon4invert"] = false, 47 | ["trackingicon4color"] = {0.00,0.60,0}, 48 | ["trackingicon5"] = {"Curse",}, 49 | ["trackingicon5invert"] = false, 50 | ["trackingicon5color"] = {0.60,0.00,1.00}, 51 | ["trackingicon6"] = {"Disease",}, 52 | ["trackingicon6invert"] = false, 53 | ["trackingicon6color"] = {0.60,0.40,0}, 54 | ["trackingicon7"] = {"Mortal Strike","Mortal Wound","Veil of Shadow","Curse of the Deadwood","Blood Fury","Wound Poison","Hex of Weakness",}, 55 | ["trackingicon7invert"] = false, 56 | ["trackingicon7color"] = {0.80,0,0}, 57 | ["trackingicon8"] = {"",}, 58 | ["trackingicon8invert"] = false, 59 | ["trackingicon8color"] = {0.20,0.60,1.00}, 60 | 61 | ["trackaggro"] = true, 62 | ["aggrowarningcolor"] = {150/255,10/255,10/255,0.8}, 63 | ["trackmana"] = true, 64 | ["manawarningcolor"] = {42/255,69/255,117/255,0.8}, 65 | 66 | ["tracktarget"] = false, 67 | ["targetcolor"] = {1,1,1,0.8}, 68 | 69 | ["containerpoint"] = "CENTER", 70 | ["containeroffx"] = 0, 71 | ["containeroffy"] = 0, 72 | 73 | ["unitnamehealthoffx"] = 0, 74 | ["unitnamehealthoffy"] = 0, 75 | 76 | 77 | ["healththreshhold"] = 90, 78 | ["manathreshhold"] = 20, 79 | ["namelength"] = 3, 80 | 81 | ["ooralpha"] = 0.5, 82 | 83 | ["useproximity"] = true, 84 | ["proximityrate"] = 1, 85 | ["proximityleeway"] = 4, 86 | 87 | ["colorunitnamehealthbyclass"] = true, 88 | ["colorunithealthbarbyclass"] = true, 89 | ["colorunithealthbarbgbyclass"] = false, 90 | ["usetbcshamancolor"] = true, 91 | ["usepetcolor"] = true, 92 | ["petcolor"] = {1,0.74,0}, 93 | 94 | 95 | ["smartcenter"] = false, 96 | ["showhealcommtext"] = true, 97 | ["showhealcommbar"] = true, 98 | ["usemapdistances"] = true, 99 | 100 | ["showwhilesolo"] = true, 101 | ["showinparty"] = true, 102 | ["showpartyinraid"] = false, 103 | ["showpets"] = false, 104 | ["showblizzframes"] = true, 105 | 106 | ["growthdirection"] = 1, -- 1: Group Left to Right, 2: Group Right to Left, 3: Group Top to Bottom, 4: Group Bottom to Top, 5: Unit Top to Bottom.. etc 107 | 108 | ["cliquehook"] = false, -- keep default false to avoid confusion from new users 109 | 110 | ["configmode"] = false, 111 | ["disablemouseoverincombat"] = false, 112 | 113 | ["borderartwork"] = false, 114 | 115 | ["draggable"] = false, 116 | ["showmenuhint"] = true, 117 | } 118 | 119 | function NotGrid:SetDefaultOptions() -- this will run on initialization and make sure everything is set. We can also use it if we wipe the NotGridOptions table and want to load it up with defaults 120 | for key,value in DefaultOptions do 121 | if not NotGridOptions[key] and not (not NotGridOptions[key] and type(NotGridOptions[key]) == "boolean") then -- if this wasn't set from the saved variable load 122 | NotGridOptions[key] = value 123 | end 124 | end 125 | --if the current version is older than a commit that caused a config change, then set the affected configs back to default 126 | if NotGridOptions.version < 1.112 and type(NotGridOptions.trackingicon1) ~= "table" then -- means they're using old aura handling and we need strings to be tables 127 | for i=1,8 do 128 | NotGridOptions["trackingicon"..i] = DefaultOptions["trackingicon"..i] 129 | end 130 | end 131 | if NotGridOptions.version < 1.106 and NotGridOptions.containerpoint ~= "CENTER" then -- means they used the old drag positioning and it will be set relative to TOPLEFT 132 | NotGridOptions.containerpoint = DefaultOptions.containerpoint 133 | NotGridOptions.containeroffx = DefaultOptions.containeroffx 134 | NotGridOptions.containeroffy = DefaultOptions.containeroffy 135 | end 136 | if NotGridOptions.version < 1.104 and type(NotGridOptions.unithealthorientation) ~= "number" then -- means they used the old editbox config and it will be set as "VERTICAL"/"HORIZONTAL" 137 | NotGridOptions.unithealthorientation = DefaultOptions.unithealthorientation 138 | end 139 | NotGridOptions.version = DefaultOptions.version --update the version 140 | end 141 | 142 | -------------------- 143 | -- Slash Commands -- 144 | -------------------- 145 | 146 | SLASH_NOTGRID1 = "/notgrid" 147 | SLASH_NOTGRID2 = "/ng" 148 | function SlashCmdList.NOTGRID(msg, editbox) 149 | if msg == "reset" then 150 | for key,value in DefaultOptions do 151 | NotGridOptions[key] = value 152 | end 153 | ReloadUI() -- we have to reloadui to make the config menu update as well 154 | elseif msg == "grid" then 155 | NotGrid.o.unithealthbartexture = "Interface\\AddOns\\NotGrid\\media\\GridGradient" 156 | NotGrid.o.unithealthbarbgtexture = "Interface\\AddOns\\NotGrid\\media\\GridGradient" 157 | NotGrid.o.unithealthbarcolor = {0,0,0,0.65} 158 | NotGrid.o.unithealthbarbgcolor = {0,0,0,1} 159 | NotGrid.o.colorunithealthbarbyclass = false 160 | NotGrid.o.colorunithealthbarbgbyclass = true 161 | ReloadUI() 162 | else 163 | NotGridOptionsMenu:Show() 164 | end 165 | end 166 | -------------------------------------------------------------------------------- /proximity.lua: -------------------------------------------------------------------------------- 1 | local L = AceLibrary("AceLocale-2.2"):new("NotGrid") 2 | 3 | local spells40yd = { -- Macros are forced to have text associated with them so we can safely just check the textures as well as check against the presence of text. No need for Gratuity or Babble overhead. Though if they have an item in their bar that matches the texture then GG haha 4 | ["PALADIN"] = {"Interface\\Icons\\Spell_Holy_FlashHeal", "Interface\\Icons\\Spell_Holy_HolyBolt"}, 5 | ["PRIEST"] = {"Interface\\Icons\\Spell_Holy_FlashHeal", "Interface\\Icons\\Spell_Holy_LesserHeal", "Interface\\Icons\\Spell_Holy_Heal", "Interface\\Icons\\Spell_Holy_GreaterHeal", "Interface\\Icons\\Spell_Holy_Renew"}, 6 | ["DRUID"] = {"Interface\\Icons\\Spell_Nature_HealingTouch", "Interface\\Icons\\Spell_Nature_ResistNature", "Interface\\Icons\\Spell_Nature_Rejuvenation"}, 7 | ["SHAMAN"] = {"Interface\\Icons\\Spell_Nature_MagicImmunity", "Interface\\Icons\\Spell_Nature_HealingWaveLesser", "Interface\\Icons\\Spell_Nature_HealingWaveGreater"}, 8 | } 9 | 10 | -------------------- 11 | -- UNIT_PROXIMITY -- 12 | -------------------- 13 | function NotGrid:UNIT_PROXIMITY() 14 | for key,f in self.UnitFrames do 15 | local unitid = f.unit 16 | if UnitExists(unitid) and f:IsVisible() then 17 | local response = self:CheckProximity(unitid) 18 | if response == 1 then 19 | self:RangeToggle(f, 1) 20 | elseif response == 2 then 21 | self:RangeToggle(f, 2) 22 | else 23 | self:RangeToggle(f, 3) 24 | end 25 | end 26 | end 27 | end 28 | 29 | 30 | function NotGrid:RangeToggle(f, condition) 31 | if condition == 1 then 32 | f.lastseen = GetTime() -- this of course makes it sort of wrong when players are switching up Unitids on rapid join/leave of group 33 | f:SetAlpha(1) 34 | elseif condition == 2 then 35 | f:SetAlpha(self.o.ooralpha) 36 | elseif (f.lastseen and (GetTime() - f.lastseen) > self.o.proximityleeway) then -- if not confirmed to be out of range, toggle him as out of range only after the proximity leeway time 37 | f:SetAlpha(self.o.ooralpha) 38 | end 39 | end 40 | 41 | ---------------- 42 | -- Main Check -- 43 | ---------------- 44 | 45 | function NotGrid:CheckProximity(unitid) -- return 1=confirmed_true, 2=confirmed_false, and no_response/false/nil means we can't confirm either way 46 | if UnitExists(unitid) and UnitIsVisible(unitid) then 47 | --check these scenarios first even if the player has check with map toggled 48 | if UnitIsUnit(unitid, "player") then --unitisplayer, 0 yards 49 | return 1 50 | elseif CheckInteractDistance(unitid, 3) then -- duel range, 10 yards 51 | return 1 52 | elseif CheckInteractDistance(unitid, 2) then -- trade and inspect range (1 is the same as 2 with patch 1.12), 11.11 yards 53 | return 1 54 | elseif CheckInteractDistance(unitid, 4) then -- follow range, 28 yards 55 | return 1 56 | elseif SpellIsTargeting() then 57 | if SpellCanTargetUnit(unitid) then 58 | return 1 59 | else 60 | return 2 61 | end 62 | elseif UnitIsUnit(unitid, "target") and self.ProximityVars.spell40slot then 63 | if IsActionInRange(self.ProximityVars.spell40slot) == 1 then -- IsActionInRange returns the string "0" if not in range which is a boolean true, so I check for 1 instead 64 | return 1 65 | else 66 | return 2 67 | end 68 | end 69 | if self.o.usemapdistances and self.ProximityVars.mapFileName and not WorldMapFrame:IsVisible() then 70 | local distance = self:GetWorldDistance(unitid) 71 | if distance then -- A nil distance would mean map error & unconfirmed distance. Otherwise confirm in range or confirm out of range 72 | if distance <= 40 then 73 | return 1 74 | else 75 | return 2 76 | end 77 | end 78 | end 79 | end 80 | end 81 | 82 | ------------------------- 83 | -- Map Proximity Stuff -- 84 | ------------------------- 85 | 86 | function NotGrid:GetWorldDistance(unitid) -- Thanks to Rhena/Renew/Astrolabe 87 | local px, py, ux, uy, distance 88 | local v = self.ProximityVars 89 | px, py = GetPlayerMapPosition("player") -- gets position data in units of percentage of map size 90 | ux, uy = GetPlayerMapPosition(unitid) 91 | if v.mapFileName and v.MapSizes[v.mapFileName] and px ~= 0 and ux ~= 0 then -- we check player and unit against absolute 0 as returning such is likely an out of bounds map error. if such is the case we'll return a nil distance 92 | local xdelta = (px - ux)*v.MapSizes[v.mapFileName].x -- (px-ux) gives distance in percentage units, multiply by mapsize to convert to wow units. 93 | local ydelta = (py - uy)*v.MapSizes[v.mapFileName].y 94 | distance = sqrt(xdelta^2 + ydelta^2)*(40/42.9) -- Then use maths distance formula for two points on a grid. include a modifiier of (40/42.9) because there seems to be 40 spell yards per 42.9 wow gps units. 95 | end 96 | return distance 97 | end 98 | 99 | function NotGrid:UpdateProximityMapVars() 100 | SetMapToCurrentZone() 101 | self.ProximityVars.mapFileName, _, _ = GetMapInfo() 102 | end 103 | 104 | ------------------------- 105 | -- Combat Event Handle -- TODO: This doesn't recognize events such as "player suffers X damage from creatures spell" is that because I found it to be erronous previously? Or an oversight? 106 | ------------------------- 107 | 108 | function NotGrid:CombatEventHandle() 109 | local combatlogrange = tonumber(GetCVar("CombatLogRangeFriendlyPlayers")) -- I'm going to inappropriately assume that if he's set this as non-default then he's also set all the others as the same(we can correct this easily in future versions) 110 | if combatlogrange <= 40 then 111 | local v = self.ProximityVars 112 | local capturestring = L.CombatEvents[event] -- "event" is the name of the event sent by the wow api 113 | local _, _, name = string.find(arg1, capturestring) -- arg1 gets sent by any combat event as the string you see in combat log, this will grab the name out of it using defined capture strings in localization.lua 114 | 115 | for _,f in self.UnitFrames do --look through unitframes for f.name? 116 | if (name and f.name) and (name == f.name) then 117 | self:RangeToggle(f, 1) 118 | end 119 | end 120 | end 121 | end 122 | 123 | ------------------------- 124 | -- 40 Yard Spell Stuff -- 125 | ------------------------- 126 | 127 | function NotGrid:GetFortyYardSpell() 128 | local v = self.ProximityVars 129 | local _, class = UnitClass("player") 130 | if spells40yd[class] then -- if player is of a class that has data in the table 131 | local textures = spells40yd[class] 132 | local indices = getn(spells40yd[class]) 133 | for i = 1, 120 do -- for all possible action bar slots 134 | local ActionTexture = GetActionTexture(i) 135 | for j=1,indices do -- for as many textures are in the class table 136 | if ActionTexture == textures[j] and not GetActionText(i) then -- if we match a texture and there is no text with it(macros are forced to have text) 137 | v.spell40slot = i -- set it as our variable and return out of the function 138 | return 139 | end 140 | end 141 | end 142 | end 143 | v.spell40slot = nil -- set it as nil if it never found anything 144 | end 145 | 146 | 147 | --------------------- 148 | -- Clique Helper -- 149 | --------------------- 150 | 151 | function NotGrid:SpellCanTarget() 152 | for _,f in self.UnitFrames do 153 | local unitid = f.unit 154 | if UnitExists(unitid) and UnitIsVisible(unitid) and SpellIsTargeting() then -- mimick the checks of the main checker and then pass results directly to RangeToggle 155 | if SpellCanTargetUnit(unitid) then 156 | self:RangeToggle(f, 1) 157 | else 158 | self:RangeToggle(f, 2) 159 | end 160 | end 161 | end 162 | end 163 | 164 | --[[ Although I've done away with NotProximityLib I still want these notes to be around. 165 | ------------------------------------------------ 166 | -- Notes About Combat Log Messages 167 | ------------------------------------------------ 168 | None of the below can be used for accurate proximity assumptions. 169 | Here's why: Combat events are limited to the likes of "(%a+) hits". There's no "(%a+) gets hit". What does this mean? Lets look at a Ragnaros encounter for an example. 170 | 171 | Player -- 0 yards 172 | Ragnaros -- 40 yards 173 | RaidMember -- 80 yards 174 | 175 | When Ragnaros hits RaidMember, Player will get the combat message "Ragnaros hits RaidMember". That's great, our assumption is now that because we see "Ragnaros hits RaidMember" that we can capture the first name of such a string and determine that Ragnaros is in range. However, when RaidMember hits Ragnaros, Player will get the event "RaidMember hits Ragnaros". Because RaidMember hit a unit that was within 40 yards of Player, Player still gets the message "RaidMember hits Ragnaros", even though the RaidMember is 80 yards away. 176 | 177 | And we're not getting any special arguments(in 1.12) sent along with these events telling us who is responsible for triggering said combat message. All we know is we got a CREATURE_HITS_PARTY_MEMBER and PARTY_MEMBER_HITS_CREATURE. There's no way to parse out whether one is further away than the other. Almost all combat messages are made useless by this fact. 178 | 179 | These are all deprecated: 180 | CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS = ".+ c?[rh]its (%a+) for .+", 181 | CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS = ".+ c?[rh]its (%a+) for .+", 182 | CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS = ".+ c?[rh]its (%a+) for .+", 183 | CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE = {".+'s .+ c?[rh]its (%a+) for .+", ".+'s .+ was resisted by (%a+)%."}, 184 | CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE = {".+'s .+ c?[rh]its (%a+) for .+", ".+'s .+ was resisted by (%a+)%."}, 185 | CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE = {".+'s .+ c?[rh]its (%a+) for .+", ".+'s .+ was resisted by (%a+)%."}, 186 | 187 | CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE = ".+'s .+ c?[rh]its (%a+) for .+", 188 | CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE = "(%a+) is afflicted by .+" 189 | 190 | CHAT_MSG_COMBAT_PARTY_HITS = "(%a+) c?[rh]its .+", 191 | CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS = "(%a+) c?[rh]its .+", 192 | 193 | CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE = "%a+ suffers %d+ %a+ damage from (%a+)'s .+" -- For this I could still read it for "(%a+) is Afflicted by" but creatures aren't in the RosterLib so its pointless. 194 | 195 | ------------------------------------------------ 196 | -- Notes About IsActionInRange() 197 | ------------------------------------------------ 198 | So the premise was we'd recognize that any healing class will have a 40yd healing spell right from the start. We could then use this spell as a default check for 40 yards for the targetted unit (its how the action bar determines whether to color them red or not) but IsActionInRange only accepts the literal button as value, not the spellname. So there's a possibility we could itterate through a player's actionbars and stop at the first 40 yard range spell we see and use that as the default, and listen for action bar changes(if thats a thing) and modify if needed. But that seems excessive, and I think we'd need to make a full table listing every 40 yard range spell to check against. 199 | 200 | Level 1 Spells: 201 | pala: Holy Light (40 yd) 202 | prie: Lesser Heal(40 yd) 203 | drui: Healing Touch(40 yd) 204 | sham: Healing Wave(40 yd) 205 | 206 | IsSpellInRange() -- TBC 207 | IsItemInRange() -- TBC 208 | IsCurrentAction() -- Useless. If you're casting and a unit runs out of range it won't fail unit it reaches the end of cast. 209 | 210 | ------------------------------------------------ 211 | -- ISSUES/BUGS 212 | ------------------------------------------------ 213 | unitischarmed -- need to handle this and not set him out of range with certain conditions 214 | ]] 215 | --------------------------------------------------------------------------------