math.lua 13.3 KB
Newer Older
Azilroka's avatar
Azilroka committed
1
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
Elv's avatar
Elv committed
2

3
--Cache global variables
4
local select, tonumber, assert, type, unpack, pairs = select, tonumber, assert, type, unpack, pairs
5
6
7
local tinsert, tremove = tinsert, tremove
local atan2, modf, ceil, floor, abs, sqrt, mod = math.atan2, math.modf, math.ceil, math.floor, math.abs, math.sqrt, mod
local format, sub, upper, split, utf8sub = string.format, string.sub, string.upper, string.split, string.utf8sub
8
9
--WoW API / Variables
local CreateFrame = CreateFrame
10
local UnitPosition = UnitPosition
11
12
13
local GetPlayerFacing = GetPlayerFacing
local BreakUpLargeNumbers = BreakUpLargeNumbers
local GetScreenWidth, GetScreenHeight = GetScreenWidth, GetScreenHeight
14
local C_Timer_After = C_Timer.After
Elv's avatar
Elv committed
15

Elv's avatar
Elv committed
16
17
--Return short value of a number
function E:ShortValue(v)
18
19
20
21
22
23
24
25
26
27
	if E.db.general.numberPrefixStyle == "METRIC" then
		if abs(v) >= 1e9 then
			return format("%.1fG", v / 1e9)
		elseif abs(v) >= 1e6 then
			return format("%.1fM", v / 1e6)
		elseif abs(v) >= 1e3 then
			return format("%.1fk", v / 1e3)
		else
			return format("%d", v)
		end
Rubgrsch's avatar
Rubgrsch committed
28
29
30
31
32
33
34
35
	elseif E.db.general.numberPrefixStyle == "CHINESE" then
		if abs(v) >= 1e8 then
			return format("%.1fY", v / 1e8)
		elseif abs(v) >= 1e4 then
			return format("%.1fW", v / 1e4)
		else
			return format("%d", v)
		end
36
37
38
39
40
41
42
43
44
45
	elseif E.db.general.numberPrefixStyle == "KOREAN" then
		if abs(v) >= 1e8 then
			return format("%.1f억", v / 1e8)
		elseif abs(v) >= 1e4 then
			return format("%.1f만", v / 1e4)
		elseif abs(v) >= 1e3 then
			return format("%.1f천", v / 1e3)
		else
			return format("%d", v)
		end
Merathilis's avatar
Merathilis committed
46
47
48
49
50
51
52
53
54
55
	elseif E.db.general.numberPrefixStyle == "GERMAN" then
		if abs(v) >= 1e9 then
			return format("%.1fMrd", v / 1e9)
		elseif abs(v) >= 1e6 then
			return format("%.1fMio", v / 1e6)
		elseif abs(v) >= 1e3 then
			return format("%.1fTsd", v / 1e3)
		else
			return format("%d", v)
		end
Elv's avatar
Elv committed
56
	else
57
58
59
60
61
62
63
64
65
		if abs(v) >= 1e9 then
			return format("%.1fB", v / 1e9)
		elseif abs(v) >= 1e6 then
			return format("%.1fM", v / 1e6)
		elseif abs(v) >= 1e3 then
			return format("%.1fK", v / 1e3)
		else
			return format("%d", v)
		end
Elv's avatar
Elv committed
66
67
68
69
	end
end

function E:IsEvenNumber(num)
70
	return num % 2 == 0
Elv's avatar
Elv committed
71
72
73
74
75
end

-- http://www.wowwiki.com/ColorGradient
function E:ColorGradient(perc, ...)
	if perc >= 1 then
Elv's avatar
Elv committed
76
		return select(select('#', ...) - 2, ...)
Elv's avatar
Elv committed
77
	elseif perc <= 0 then
Elv's avatar
Elv committed
78
		return ...
Elv's avatar
Elv committed
79
80
81
	end

	local num = select('#', ...) / 3
Elv's avatar
Elv committed
82
	local segment, relperc = modf(perc*(num-1))
Elv's avatar
Elv committed
83
84
85
86
87
88
	local r1, g1, b1, r2, g2, b2 = select((segment*3)+1, ...)

	return r1 + (r2-r1)*relperc, g1 + (g2-g1)*relperc, b1 + (b2-b1)*relperc
end

--Return rounded number
89
90
91
92
93
94
function E:Round(num, idp)
	if(idp and idp > 0) then
		local mult = 10 ^ idp
		return floor(num * mult + 0.5) / mult
	end
	return floor(num + 0.5)
Elv's avatar
Elv committed
95
96
97
98
end

--Truncate a number off to n places
function E:Truncate(v, decimals)
99
	return v - (v % (0.1 ^ (decimals or 0)))
Elv's avatar
Elv committed
100
101
102
103
104
105
106
end

--RGB to Hex
function E:RGBToHex(r, g, b)
	r = r <= 1 and r >= 0 and r or 0
	g = g <= 1 and g >= 0 and g or 0
	b = b <= 1 and b >= 0 and b or 0
Elv's avatar
Elv committed
107
	return format("|cff%02x%02x%02x", r*255, g*255, b*255)
Elv's avatar
Elv committed
108
109
110
111
end

--Hex to RGB
function E:HexToRGB(hex)
Elv's avatar
Elv committed
112
	local rhex, ghex, bhex = sub(hex, 1, 2), sub(hex, 3, 4), sub(hex, 5, 6)
Elv's avatar
Elv committed
113
114
115
	return tonumber(rhex, 16), tonumber(ghex, 16), tonumber(bhex, 16)
end

116
117
--From http://wow.gamepedia.com/UI_coordinates
function E:FramesOverlap(frameA, frameB)
118
119
	if not frameA or not frameB then return	end

120
	local sA, sB = frameA:GetEffectiveScale(), frameB:GetEffectiveScale();
121
122
123
124
125
126
	if not sA or not sB then return	end

	local frameALeft = frameA:GetLeft()
	local frameARight = frameA:GetRight()
	local frameABottom = frameA:GetBottom()
	local frameATop = frameA:GetTop()
127

128
129
130
131
132
133
134
	local frameBLeft = frameB:GetLeft()
	local frameBRight = frameB:GetRight()
	local frameBBottom = frameB:GetBottom()
	local frameBTop = frameB:GetTop()

	if not frameALeft or not frameARight or not frameABottom or not frameATop then return end
	if not frameBLeft or not frameBRight or not frameBBottom or not frameBTop then return end
135

136
137
138
139
	return ((frameALeft*sA) < (frameBRight*sB))
		and ((frameBLeft*sB) < (frameARight*sA))
		and ((frameABottom*sA) < (frameBTop*sB))
		and ((frameBBottom*sB) < (frameATop*sA));
140
141
end

Elv's avatar
Elv committed
142
143
144
145
146
function E:GetScreenQuadrant(frame)
	local x, y = frame:GetCenter()
	local screenWidth = GetScreenWidth()
	local screenHeight = GetScreenHeight()
	local point
147

Elv's avatar
Elv committed
148
149
150
	if not frame:GetCenter() then
		return "UNKNOWN", frame:GetName()
	end
151

152
	if (x > (screenWidth / 3) and x < (screenWidth / 3)*2) and y > (screenHeight / 3)*2 then
Elv's avatar
Elv committed
153
		point = "TOP"
154
	elseif x < (screenWidth / 3) and y > (screenHeight / 3)*2 then
Elv's avatar
Elv committed
155
		point = "TOPLEFT"
156
	elseif x > (screenWidth / 3)*2 and y > (screenHeight / 3)*2 then
Elv's avatar
Elv committed
157
		point = "TOPRIGHT"
158
	elseif (x > (screenWidth / 3) and x < (screenWidth / 3)*2) and y < (screenHeight / 3) then
Elv's avatar
Elv committed
159
		point = "BOTTOM"
160
	elseif x < (screenWidth / 3) and y < (screenHeight / 3) then
Elv's avatar
Elv committed
161
		point = "BOTTOMLEFT"
162
	elseif x > (screenWidth / 3)*2 and y < (screenHeight / 3) then
Elv's avatar
Elv committed
163
		point = "BOTTOMRIGHT"
164
	elseif x < (screenWidth / 3) and (y > (screenHeight / 3) and y < (screenHeight / 3)*2) then
Elv's avatar
Elv committed
165
		point = "LEFT"
166
	elseif x > (screenWidth / 3)*2 and y < (screenHeight / 3)*2 and y > (screenHeight / 3) then
Elv's avatar
Elv committed
167
168
169
170
171
172
173
174
		point = "RIGHT"
	else
		point = "CENTER"
	end

	return point
end

Elv's avatar
Elv committed
175
function E:GetXYOffset(position, override)
176
	local default = E.Spacing
177
	local x, y = override or default, override or default
178

179
	if position == 'TOP' then
Elv's avatar
Elv committed
180
		return 0, y
181
182
183
184
185
	elseif position == 'TOPLEFT' then
		return x, y
	elseif position == 'TOPRIGHT' then
		return -x, y
	elseif position == 'BOTTOM' then --or  or  then
Elv's avatar
Elv committed
186
		return 0, -y
187
188
189
190
	elseif position == 'BOTTOMLEFT' then
		return x, -y
	elseif position == 'BOTTOMRIGHT' then
		return -x, -y
Elv's avatar
Elv committed
191
192
	elseif position == 'LEFT' then
		return -x, 0
193
	elseif position == 'RIGHT' then
Elv's avatar
Elv committed
194
		return x, 0
195
196
	elseif position == "CENTER" then
		return 0, 0
Elv's avatar
Elv committed
197
198
199
200
201
202
	end
end

local styles = {
	['CURRENT'] = '%s',
	['CURRENT_MAX'] = '%s - %s',
Blazeflack's avatar
Blazeflack committed
203
204
205
	['CURRENT_PERCENT'] =  '%s - %.1f%%',
	['CURRENT_MAX_PERCENT'] = '%s - %s | %.1f%%',
	['PERCENT'] = '%.1f%%',
Elv's avatar
Elv committed
206
207
208
209
210
211
212
	['DEFICIT'] = '-%s'
}

function E:GetFormattedText(style, min, max)
	assert(styles[style], 'Invalid format style: '..style)
	assert(min, 'You need to provide a current value. Usage: E:GetFormattedText(style, min, max)')
	assert(max, 'You need to provide a maximum value. Usage: E:GetFormattedText(style, min, max)')
213

Elv's avatar
Elv committed
214
	if max == 0 then max = 1 end
215

Elv's avatar
Elv committed
216
217
218
219
220
221
222
	local useStyle = styles[style]

	if style == 'DEFICIT' then
		local deficit = max - min
		if deficit <= 0 then
			return ''
		else
Elv's avatar
Elv committed
223
			return format(useStyle, E:ShortValue(deficit))
Elv's avatar
Elv committed
224
225
		end
	elseif style == 'PERCENT' then
Blazeflack's avatar
Blazeflack committed
226
		local s = format(useStyle, min / max * 100)
Elv's avatar
Elv committed
227
		return s
Elv's avatar
Elv committed
228
	elseif style == 'CURRENT' or ((style == 'CURRENT_MAX' or style == 'CURRENT_MAX_PERCENT' or style == 'CURRENT_PERCENT') and min == max) then
Elv's avatar
Elv committed
229
		return format(styles['CURRENT'],  E:ShortValue(min))
Elv's avatar
Elv committed
230
	elseif style == 'CURRENT_MAX' then
Elv's avatar
Elv committed
231
		return format(useStyle,  E:ShortValue(min), E:ShortValue(max))
Elv's avatar
Elv committed
232
	elseif style == 'CURRENT_PERCENT' then
Blazeflack's avatar
Blazeflack committed
233
		local s = format(useStyle, E:ShortValue(min), min / max * 100)
Elv's avatar
Elv committed
234
		return s
Elv's avatar
Elv committed
235
	elseif style == 'CURRENT_MAX_PERCENT' then
Blazeflack's avatar
Blazeflack committed
236
		local s = format(useStyle, E:ShortValue(min), E:ShortValue(max), min / max * 100)
Elv's avatar
Elv committed
237
		return s
Elv's avatar
Elv committed
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
	end
end

function E:ShortenString(string, numChars, dots)
	local bytes = string:len()
	if (bytes <= numChars) then
		return string
	else
		local len, pos = 0, 1
		while(pos <= bytes) do
			len = len + 1
			local c = string:byte(pos)
			if (c > 0 and c <= 127) then
				pos = pos + 1
			elseif (c >= 192 and c <= 223) then
				pos = pos + 2
			elseif (c >= 224 and c <= 239) then
				pos = pos + 3
			elseif (c >= 240 and c <= 247) then
				pos = pos + 4
			end
			if (len == numChars) then break end
		end

		if (len == numChars and pos <= bytes) then
			return string:sub(1, pos - 1)..(dots and '...' or '')
		else
			return string
		end
	end
end

270
function E:AbbreviateString(string, allUpper)
271
272
273
	local newString = ""
	local words = {split(" ", string)}
	for _, word in pairs(words) do
274
		word = utf8sub(word, 1, 1) --get only first letter of each word
275
276
277
278
279
280
281
		if(allUpper) then
			word = word:upper()
		end
		newString = newString .. word
	end

	return newString
282
283
end

Elv's avatar
Elv committed
284
285
286
287
288
289
290
--Add time before calling a function
local waitTable = {}
local waitFrame
function E:Delay(delay, func, ...)
	if(type(delay)~="number" or type(func)~="function") then
		return false
	end
291
292
293
294
295
296
297
298
299
300
301
302
	local extend = {...}
	if not next(extend) then
		C_Timer_After(delay, func)
		return true
	else
		if(waitFrame == nil) then
			waitFrame = CreateFrame("Frame","WaitFrame", E.UIParent)
			waitFrame:SetScript("onUpdate",function (_,elapse)
				local count = #waitTable
				local i = 1
				while(i<=count) do
					local waitRecord = tremove(waitTable,i)
303
304
305
306
307
					local delay = tremove(waitRecord,1)
					local func = tremove(waitRecord,1)
					local params = tremove(waitRecord,1)
					if(delay>elapse) then
					  tinsert(waitTable,i,{delay-elapse,func,params})
308
309
310
					  i = i + 1
					else
					  count = count - 1
311
					  func(unpack(params))
312
					end
Elv's avatar
Elv committed
313
				end
314
315
316
317
			end)
		end
		tinsert(waitTable,{delay,func,extend})
		return true
Elv's avatar
Elv committed
318
319
320
321
	end
end

function E:StringTitle(str)
Elv's avatar
Elv committed
322
	return str:gsub("(.)", upper, 1)
Elv's avatar
Elv committed
323
324
325
326
327
328
329
330
331
332
333
334
335
end

-- aura time colors for days, hours, minutes, seconds, fadetimer
E.TimeColors = {
	[0] = '|cffeeeeee',
	[1] = '|cffeeeeee',
	[2] = '|cffeeeeee',
	[3] = '|cffeeeeee',
	[4] = '|cfffe0000',
}

-- short and long aura time formats
E.TimeFormats = {
336
337
338
339
340
	[0] = { '%dd', '%dd' },
	[1] = { '%dh', '%dh' },
	[2] = { '%dm', '%dm' },
	[3] = { '%ds', '%d' },
	[4] = { '%.1fs', '%.1f' },
341
}
Elv's avatar
Elv committed
342

Elv's avatar
Elv committed
343

Elv's avatar
Elv committed
344
local DAY, HOUR, MINUTE = 86400, 3600, 60 --used for calculating aura time text
345
local DAYISH, HOURISH, MINUTEISH = HOUR * 23.5, MINUTE * 59.5, 59.5 --used for caclculating aura time at transition points
Elv's avatar
Elv committed
346
347
348
local HALFDAYISH, HALFHOURISH, HALFMINUTEISH = DAY/2 + 0.5, HOUR/2 + 0.5, MINUTE/2 + 0.5 --used for calculating next update times

-- will return the the value to display, the formatter id to use and calculates the next update for the Aura
349
function E:GetTimeInfo(s, threshhold)
Elv's avatar
Elv committed
350
351
352
353
354
355
356
	if s < MINUTE then
		if s >= threshhold then
			return floor(s), 3, 0.51
		else
			return s, 4, 0.051
		end
	elseif s < HOUR then
357
		local minutes = floor((s/MINUTE)+.5)
358
		return ceil(s / MINUTE), 2, minutes > 1 and (s - (minutes*MINUTE - HALFMINUTEISH)) or (s - MINUTEISH)
Elv's avatar
Elv committed
359
	elseif s < DAY then
360
		local hours = floor((s/HOUR)+.5)
Elv's avatar
Elv committed
361
362
		return ceil(s / HOUR), 1, hours > 1 and (s - (hours*HOUR - HALFHOURISH)) or (s - HOURISH)
	else
363
		local days = floor((s/DAY)+.5)
Elv's avatar
Elv committed
364
365
		return ceil(s / DAY), 0,  days > 1 and (s - (days*DAY - HALFDAYISH)) or (s - DAYISH)
	end
366
367
end

368
369
function E:GetDistance(unit1, unit2)
	local x1, y1, _, map1 = UnitPosition(unit1)
370

371
	if not x1 then return end
Elv's avatar
Elv committed
372

373
	local x2, y2, _, map2 = UnitPosition(unit2)
Elv's avatar
Elv committed
374

375
	if not x2 then return end
Elv's avatar
Elv committed
376

377
	if map1 ~= map2 then return end
Elv's avatar
Elv committed
378

379
380
381
	local dX = x2 - x1
	local dY = y2 - y1
	local distance = sqrt(dX * dX + dY * dY)
Elv's avatar
Elv committed
382

383
	return distance, atan2(dY, dX) - GetPlayerFacing()
384
385
386
387
388
389
390
391
392
393
end

--Money text formatting, code taken from Scrooge by thelibrarian ( http://www.wowace.com/addons/scrooge/ )
local COLOR_COPPER = "|cffeda55f"
local COLOR_SILVER = "|cffc7c7cf"
local COLOR_GOLD = "|cffffd700"
local ICON_COPPER = "|TInterface\\MoneyFrame\\UI-CopperIcon:12:12|t"
local ICON_SILVER = "|TInterface\\MoneyFrame\\UI-SilverIcon:12:12|t"
local ICON_GOLD = "|TInterface\\MoneyFrame\\UI-GoldIcon:12:12|t"
function E:FormatMoney(amount, style, textonly)
Rubgrsch's avatar
Rubgrsch committed
394
395
396
	local coppername = textonly and L["copperabbrev"] or ICON_COPPER
	local silvername = textonly and L["silverabbrev"] or ICON_SILVER
	local goldname = textonly and L["goldabbrev"] or ICON_GOLD
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460

	local value = abs(amount)
	local gold = floor(value / 10000)
	local silver = floor(mod(value / 100, 100))
	local copper = floor(mod(value, 100))

	if not style or style == "SMART" then
		local str = "";
		if gold > 0 then
			str = format("%d%s%s", gold, goldname, (silver > 0 or copper > 0) and " " or "")
		end
		if silver > 0 then
			str = format("%s%d%s%s", str, silver, silvername, copper > 0 and " " or "")
		end
		if copper > 0 or value == 0 then
			str = format("%s%d%s", str, copper, coppername)
		end
		return str
	end

	if style == "FULL" then
		if gold > 0 then
			return format("%d%s %d%s %d%s", gold, goldname, silver, silvername, copper, coppername)
		elseif silver > 0 then
			return format("%d%s %d%s", silver, silvername, copper, coppername)
		else
			return format("%d%s", copper, coppername)
		end
	elseif style == "SHORT" then
		if gold > 0 then
			return format("%.1f%s", amount / 10000, goldname)
		elseif silver > 0 then
			return format("%.1f%s", amount / 100, silvername)
		else
			return format("%d%s", amount, coppername)
		end
	elseif style == "SHORTINT" then
		if gold > 0 then
			return format("%d%s", gold, goldname)
		elseif silver > 0 then
			return format("%d%s", silver, silvername)
		else
			return format("%d%s", copper, coppername)
		end
	elseif style == "CONDENSED" then
		if gold > 0 then
			return format("%s%d|r.%s%02d|r.%s%02d|r", COLOR_GOLD, gold, COLOR_SILVER, silver, COLOR_COPPER, copper)
		elseif silver > 0 then
			return format("%s%d|r.%s%02d|r", COLOR_SILVER, silver, COLOR_COPPER, copper)
		else
			return format("%s%d|r", COLOR_COPPER, copper)
		end
	elseif style == "BLIZZARD" then
		if gold > 0 then
			return format("%s%s %d%s %d%s", BreakUpLargeNumbers(gold), goldname, silver, silvername, copper, coppername)
		elseif silver > 0 then
			return format("%d%s %d%s", silver, silvername, copper, coppername)
		else
			return format("%d%s", copper, coppername)
		end
	end

	-- Shouldn't be here; punt
	return self:FormatMoney(amount, "SMART")
Blazeflack's avatar
Blazeflack committed
461
end